| 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 an incomplete image. This ensures any uniniti
alized |
| 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()); |
| 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(currentSubsetWidth, current
SubsetHeight); | 437 SkIRect bounds = SkIRect::MakeWH(currentSubsetWidth, current
SubsetHeight); |
| 445 SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, boun
ds)); | 438 SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, boun
ds)); |
| 446 SkAutoLockPixels autlockSubsetBm(subsetBm, true); | 439 SkAutoLockPixels autlockSubsetBm(subsetBm, true); |
| 447 const SkCodec::Result subsetResult = | 440 codec->getScanlines(buffer, currentSubsetHeight, rowBytes); |
| 448 codec->getScanlines(buffer, currentSubsetHeight, row
Bytes); | 441 |
| 449 switch (subsetResult) { | |
| 450 case SkCodec::kSuccess: | |
| 451 case SkCodec::kIncompleteInput: | |
| 452 break; | |
| 453 default: | |
| 454 return SkStringPrintf("%s failed with error message
%d", | |
| 455 fPath.c_str(), (int) subsetResult); | |
| 456 } | |
| 457 const size_t bpp = decodeInfo.bytesPerPixel(); | 442 const size_t bpp = decodeInfo.bytesPerPixel(); |
| 458 /* | |
| 459 * we copy all the lines at once becuase when calling getSca
nlines for | |
| 460 * interlaced pngs the entire image must be read regardless
of the number | |
| 461 * of lines requested. Reading an interlaced png in a loop,
line-by-line, would | |
| 462 * decode the entire image height times, which is very slow | |
| 463 * it is aknowledged that copying each line as you read it i
n a loop | |
| 464 * may be faster for other types of images. Since this is a
correctness test | |
| 465 * that's okay. | |
| 466 */ | |
| 467 char* bufferRow = buffer; | 443 char* bufferRow = buffer; |
| 468 for (int subsetY = 0; subsetY < currentSubsetHeight; ++subse
tY) { | 444 for (int subsetY = 0; subsetY < currentSubsetHeight; ++subse
tY) { |
| 469 memcpy(subsetBm.getAddr(0, subsetY), bufferRow + x*bpp, | 445 memcpy(subsetBm.getAddr(0, subsetY), bufferRow + x*bpp, |
| 470 currentSubsetWidth*bpp); | 446 currentSubsetWidth*bpp); |
| 471 bufferRow += rowBytes; | 447 bufferRow += rowBytes; |
| 472 } | 448 } |
| 473 | 449 |
| 474 subsetBm.notifyPixelsChanged(); | 450 subsetBm.notifyPixelsChanged(); |
| 475 canvas->drawBitmap(subsetBm, SkIntToScalar(x), SkIntToScalar
(y)); | 451 canvas->drawBitmap(subsetBm, SkIntToScalar(x), SkIntToScalar
(y)); |
| 476 } | 452 } |
| 477 } | 453 } |
| 478 break; | 454 break; |
| 479 } | 455 } |
| 480 case kStripe_Mode: { | 456 case kStripe_Mode: { |
| 481 const int height = decodeInfo.height(); | 457 const int height = decodeInfo.height(); |
| 482 // This value is chosen arbitrarily. We exercise more cases by choo
sing a value that | 458 // This value is chosen arbitrarily. We exercise more cases by choo
sing a value that |
| 483 // does not align with image blocks. | 459 // does not align with image blocks. |
| 484 const int stripeHeight = 37; | 460 const int stripeHeight = 37; |
| 485 const int numStripes = (height + stripeHeight - 1) / stripeHeight; | 461 const int numStripes = (height + stripeHeight - 1) / stripeHeight; |
| 486 | 462 |
| 487 // Decode odd stripes | 463 // Decode odd stripes |
| 488 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL
, colorPtr, | 464 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL
, colorPtr, |
| 489 colorCountPtr) | 465 colorCountPtr) |
| 490 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOr
der()) { | 466 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOr
der()) { |
| 491 // This mode was designed to test the new skip scanlines API in
libjpeg-turbo. | 467 // This mode was designed to test the new skip scanlines API in
libjpeg-turbo. |
| 492 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is
not interesting | 468 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is
not interesting |
| 493 // to run this test for image types that do not have this scanli
ne ordering. | 469 // to run this test for image types that do not have this scanli
ne ordering. |
| 494 return Error::Nonfatal("Could not start top-down scanline decode
r"); | 470 return Error::Nonfatal("Could not start top-down scanline decode
r"); |
| 495 } | 471 } |
| 472 |
| 496 for (int i = 0; i < numStripes; i += 2) { | 473 for (int i = 0; i < numStripes; i += 2) { |
| 497 // Skip a stripe | 474 // Skip a stripe |
| 498 const int linesToSkip = SkTMin(stripeHeight, height - i * stripe
Height); | 475 const int linesToSkip = SkTMin(stripeHeight, height - i * stripe
Height); |
| 499 SkCodec::Result result = codec->skipScanlines(linesToSkip); | 476 codec->skipScanlines(linesToSkip); |
| 500 switch (result) { | |
| 501 case SkCodec::kSuccess: | |
| 502 case SkCodec::kIncompleteInput: | |
| 503 break; | |
| 504 default: | |
| 505 return SkStringPrintf("Cannot skip scanlines for %s.", f
Path.c_str()); | |
| 506 } | |
| 507 | 477 |
| 508 // Read a stripe | 478 // Read a stripe |
| 509 const int startY = (i + 1) * stripeHeight; | 479 const int startY = (i + 1) * stripeHeight; |
| 510 const int linesToRead = SkTMin(stripeHeight, height - startY); | 480 const int linesToRead = SkTMin(stripeHeight, height - startY); |
| 511 if (linesToRead > 0) { | 481 if (linesToRead > 0) { |
| 512 result = codec->getScanlines(bitmap.getAddr(0, startY), | 482 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead,
bitmap.rowBytes()); |
| 513 linesToRead, bitmap.rowBytes()); | |
| 514 switch (result) { | |
| 515 case SkCodec::kSuccess: | |
| 516 case SkCodec::kIncompleteInput: | |
| 517 break; | |
| 518 default: | |
| 519 return SkStringPrintf("Cannot get scanlines for %s."
, fPath.c_str()); | |
| 520 } | |
| 521 } | 483 } |
| 522 } | 484 } |
| 523 | 485 |
| 524 // Decode even stripes | 486 // Decode even stripes |
| 525 const SkCodec::Result startResult = codec->startScanlineDecode(decod
eInfo, nullptr, | 487 const SkCodec::Result startResult = codec->startScanlineDecode(decod
eInfo, nullptr, |
| 526 colorPtr, colorCountPtr); | 488 colorPtr, colorCountPtr); |
| 527 if (SkCodec::kSuccess != startResult) { | 489 if (SkCodec::kSuccess != startResult) { |
| 528 return "Failed to restart scanline decoder with same parameters.
"; | 490 return "Failed to restart scanline decoder with same parameters.
"; |
| 529 } | 491 } |
| 530 for (int i = 0; i < numStripes; i += 2) { | 492 for (int i = 0; i < numStripes; i += 2) { |
| 531 // Read a stripe | 493 // Read a stripe |
| 532 const int startY = i * stripeHeight; | 494 const int startY = i * stripeHeight; |
| 533 const int linesToRead = SkTMin(stripeHeight, height - startY); | 495 const int linesToRead = SkTMin(stripeHeight, height - startY); |
| 534 SkCodec::Result result = codec->getScanlines(bitmap.getAddr(0, s
tartY), | 496 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitm
ap.rowBytes()); |
| 535 linesToRead, bitmap.rowBytes()); | |
| 536 switch (result) { | |
| 537 case SkCodec::kSuccess: | |
| 538 case SkCodec::kIncompleteInput: | |
| 539 break; | |
| 540 default: | |
| 541 return SkStringPrintf("Cannot get scanlines for %s.", fP
ath.c_str()); | |
| 542 } | |
| 543 | 497 |
| 544 // Skip a stripe | 498 // Skip a stripe |
| 545 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) *
stripeHeight); | 499 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) *
stripeHeight); |
| 546 if (linesToSkip > 0) { | 500 if (linesToSkip > 0) { |
| 547 result = codec->skipScanlines(linesToSkip); | 501 codec->skipScanlines(linesToSkip); |
| 548 switch (result) { | |
| 549 case SkCodec::kSuccess: | |
| 550 case SkCodec::kIncompleteInput: | |
| 551 break; | |
| 552 default: | |
| 553 return SkStringPrintf("Cannot skip scanlines for %s.
", fPath.c_str()); | |
| 554 } | |
| 555 } | 502 } |
| 556 } | 503 } |
| 557 canvas->drawBitmap(bitmap, 0, 0); | 504 canvas->drawBitmap(bitmap, 0, 0); |
| 558 break; | 505 break; |
| 559 } | 506 } |
| 560 case kSubset_Mode: { | 507 case kSubset_Mode: { |
| 561 // Arbitrarily choose a divisor. | 508 // Arbitrarily choose a divisor. |
| 562 int divisor = 2; | 509 int divisor = 2; |
| 563 // Total width/height of the image. | 510 // Total width/height of the image. |
| 564 const int W = codec->getInfo().width(); | 511 const int W = codec->getInfo().width(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 585 for (int x = 0; x < W; x += w) { | 532 for (int x = 0; x < W; x += w) { |
| 586 int top = 0; | 533 int top = 0; |
| 587 for (int y = 0; y < H; y+= h) { | 534 for (int y = 0; y < H; y+= h) { |
| 588 // Do not make the subset go off the edge of the image. | 535 // Do not make the subset go off the edge of the image. |
| 589 const int preScaleW = SkTMin(w, W - x); | 536 const int preScaleW = SkTMin(w, W - x); |
| 590 const int preScaleH = SkTMin(h, H - y); | 537 const int preScaleH = SkTMin(h, H - y); |
| 591 subset.setXYWH(x, y, preScaleW, preScaleH); | 538 subset.setXYWH(x, y, preScaleW, preScaleH); |
| 592 // And scale | 539 // And scale |
| 593 // FIXME: Should we have a version of getScaledDimensions th
at takes a subset | 540 // FIXME: Should we have a version of getScaledDimensions th
at takes a subset |
| 594 // into account? | 541 // into account? |
| 595 decodeInfo = decodeInfo.makeWH(SkScalarRoundToInt(preScaleW
* fScale), | 542 decodeInfo = decodeInfo.makeWH( |
| 596 SkScalarRoundToInt(preScaleH
* fScale)); | 543 SkTMax(1, SkScalarRoundToInt(preScaleW * fScale)), |
| 544 SkTMax(1, SkScalarRoundToInt(preScaleH * fScale))); |
| 597 size_t rowBytes = decodeInfo.minRowBytes(); | 545 size_t rowBytes = decodeInfo.minRowBytes(); |
| 598 if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes, co
lorTable.get(), | 546 if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes, co
lorTable.get(), |
| 599 nullptr, nullptr)) { | 547 nullptr, nullptr)) { |
| 600 return SkStringPrintf("could not install pixels for %s."
, fPath.c_str()); | 548 return SkStringPrintf("could not install pixels for %s."
, fPath.c_str()); |
| 601 } | 549 } |
| 602 const SkCodec::Result result = codec->getPixels(decodeInfo,
pixels, rowBytes, | 550 const SkCodec::Result result = codec->getPixels(decodeInfo,
pixels, rowBytes, |
| 603 &opts, colorPtr, colorCountPtr); | 551 &opts, colorPtr, colorCountPtr); |
| 604 switch (result) { | 552 switch (result) { |
| 605 case SkCodec::kSuccess: | 553 case SkCodec::kSuccess: |
| 606 case SkCodec::kIncompleteInput: | 554 case SkCodec::kIncompleteInput: |
| (...skipping 649 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1256 skr.visit<void>(i, drawsAsSingletonPictures); | 1204 skr.visit<void>(i, drawsAsSingletonPictures); |
| 1257 } | 1205 } |
| 1258 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); | 1206 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); |
| 1259 | 1207 |
| 1260 canvas->drawPicture(macroPic); | 1208 canvas->drawPicture(macroPic); |
| 1261 return ""; | 1209 return ""; |
| 1262 }); | 1210 }); |
| 1263 } | 1211 } |
| 1264 | 1212 |
| 1265 } // namespace DM | 1213 } // namespace DM |
| OLD | NEW |