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 |