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 |