Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Public Types | Public Member Functions | List of all members
DM::CodecSrc Class Reference

#include <DMSrcSink.h>

Inheritance diagram for DM::CodecSrc:
DM::Src

Public Types

enum  Mode {
  kCodec_Mode , kCodecZeroInit_Mode , kScanline_Mode , kStripe_Mode ,
  kCroppedScanline_Mode , kSubset_Mode , kAnimated_Mode
}
 
enum  DstColorType { kGetFromCanvas_DstColorType , kGrayscale_Always_DstColorType , kNonNative8888_Always_DstColorType }
 
- Public Types inherited from DM::Src
using GraphiteTestContext = skiatest::graphite::GraphiteTestContext
 

Public Member Functions

 CodecSrc (Path, Mode, DstColorType, SkAlphaType, float)
 
Result draw (SkCanvas *, GraphiteTestContext *) const override
 
SkISize size () const override
 
Name name () const override
 
bool veto (SinkFlags) const override
 
bool serial () const override
 
- Public Member Functions inherited from DM::Src
virtual ~Src ()
 
virtual void modifyGrContextOptions (GrContextOptions *) const
 
virtual void modifyGraphiteContextOptions (skgpu::graphite::ContextOptions *) const
 
virtual int pageCount () const
 
virtual Result draw (int page, SkCanvas *canvas, GraphiteTestContext *graphiteTestContext) const
 
virtual SkISize size (int page) const
 

Detailed Description

Definition at line 152 of file DMSrcSink.h.

Member Enumeration Documentation

◆ DstColorType

Enumerator
kGetFromCanvas_DstColorType 
kGrayscale_Always_DstColorType 
kNonNative8888_Always_DstColorType 

Definition at line 166 of file DMSrcSink.h.

◆ Mode

Enumerator
kCodec_Mode 
kCodecZeroInit_Mode 
kScanline_Mode 
kStripe_Mode 
kCroppedScanline_Mode 
kSubset_Mode 
kAnimated_Mode 

Definition at line 154 of file DMSrcSink.h.

154 {
156 // We choose to test only one mode with zero initialized memory.
157 // This will exercise all of the interesting cases in SkSwizzler
158 // without doubling the size of our test suite.
161 kStripe_Mode, // Tests the skipping of scanlines
162 kCroppedScanline_Mode, // Tests (jpeg) cropped scanline optimization
163 kSubset_Mode, // For codecs that support subsets directly.
164 kAnimated_Mode, // For codecs that support animation.
165 };
@ kCroppedScanline_Mode
Definition DMSrcSink.h:162
@ kCodecZeroInit_Mode
Definition DMSrcSink.h:159

Constructor & Destructor Documentation

◆ CodecSrc()

DM::CodecSrc::CodecSrc ( Path  path,
Mode  mode,
DstColorType  dstColorType,
SkAlphaType  dstAlphaType,
float  scale 
)

Definition at line 395 of file DMSrcSink.cpp.

397 : fPath(path)
398 , fMode(mode)
399 , fDstColorType(dstColorType)
400 , fDstAlphaType(dstAlphaType)
401 , fScale(scale)
402 , fRunSerially(serial_from_path_name(path))
403{}
static bool serial_from_path_name(const SkString &path)
const Scalar scale

Member Function Documentation

◆ draw()

Result DM::CodecSrc::draw ( SkCanvas canvas,
GraphiteTestContext  
) const
overridevirtual

Implements DM::Src.

Definition at line 474 of file DMSrcSink.cpp.

474 {
476 if (!encoded) {
477 return Result::Fatal("Couldn't read %s.", fPath.c_str());
478 }
479
480 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
481 if (nullptr == codec) {
482 return Result::Fatal("Couldn't create codec for %s.", fPath.c_str());
483 }
484
485 SkImageInfo decodeInfo = codec->getInfo();
486 if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
487 fDstAlphaType)) {
488 return Result::Skip("Skipping uninteresting test.");
489 }
490
491 // Try to scale the image if it is desired
492 SkISize size = codec->getScaledDimensions(fScale);
493
494 std::unique_ptr<SkAndroidCodec> androidCodec;
495 if (1.0f != fScale && fMode == kAnimated_Mode) {
496 androidCodec = SkAndroidCodec::MakeFromData(encoded);
497 size = androidCodec->getSampledDimensions(1 / fScale);
498 }
499
500 if (size == decodeInfo.dimensions() && 1.0f != fScale) {
501 return Result::Skip("Test without scaling is uninteresting.");
502 }
503
504 // Visually inspecting very small output images is not necessary. We will
505 // cover these cases in unit testing.
506 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
507 return Result::Skip("Scaling very small images is uninteresting.");
508 }
509 decodeInfo = decodeInfo.makeDimensions(size);
510
511 const int bpp = decodeInfo.bytesPerPixel();
512 const size_t rowBytes = size.width() * bpp;
513 const size_t safeSize = decodeInfo.computeByteSize(rowBytes);
514 SkAutoMalloc pixels(safeSize);
515
517 if (kCodecZeroInit_Mode == fMode) {
518 memset(pixels.get(), 0, size.height() * rowBytes);
519 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
520 }
521
522 SkImageInfo bitmapInfo = decodeInfo;
523 set_bitmap_color_space(&bitmapInfo);
524 if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
525 kBGRA_8888_SkColorType == decodeInfo.colorType()) {
526 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
527 }
528
529 switch (fMode) {
530 case kAnimated_Mode: {
531 SkAndroidCodec::AndroidOptions androidOptions;
532 if (fScale != 1.0f) {
533 SkASSERT(androidCodec);
534 androidOptions.fSampleSize = 1 / fScale;
535 auto dims = androidCodec->getSampledDimensions(androidOptions.fSampleSize);
536 decodeInfo = decodeInfo.makeDimensions(dims);
537 }
538
539 std::vector<SkCodec::FrameInfo> frameInfos = androidCodec
540 ? androidCodec->codec()->getFrameInfo() : codec->getFrameInfo();
541 if (frameInfos.size() <= 1) {
542 return Result::Fatal("%s is not an animated image.", fPath.c_str());
543 }
544
545 // As in CodecSrc::size(), compute a roughly square grid to draw the frames
546 // into. "factor" is the number of frames to draw on one row. There will be
547 // up to "factor" rows as well.
548 const float root = sqrt((float) frameInfos.size());
549 const int factor = sk_float_ceil2int(root);
550
551 // Used to cache a frame that future frames will depend on.
552 SkAutoMalloc priorFramePixels;
553 int cachedFrame = SkCodec::kNoFrame;
554 for (int i = 0; static_cast<size_t>(i) < frameInfos.size(); i++) {
555 androidOptions.fFrameIndex = i;
556 // Check for a prior frame
557 const int reqFrame = frameInfos[i].fRequiredFrame;
558 if (reqFrame != SkCodec::kNoFrame && reqFrame == cachedFrame
559 && priorFramePixels.get()) {
560 // Copy into pixels
561 memcpy(pixels.get(), priorFramePixels.get(), safeSize);
562 androidOptions.fPriorFrame = reqFrame;
563 } else {
564 androidOptions.fPriorFrame = SkCodec::kNoFrame;
565 }
566 SkCodec::Result result = androidCodec
567 ? androidCodec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes,
568 &androidOptions)
569 : codec->getPixels(decodeInfo, pixels.get(), rowBytes, &androidOptions);
570 if (SkCodec::kInvalidInput == result && i > 0) {
571 // Some of our test images have truncated later frames. Treat that
572 // the same as incomplete.
574 }
575 switch (result) {
579 // If the next frame depends on this one, store it in priorFrame.
580 // It is possible that we may discard a frame that future frames depend on,
581 // but the codec will simply redecode the discarded frame.
582 // Do this before calling draw_to_canvas, which premultiplies in place. If
583 // we're decoding to unpremul, we want to pass the unmodified frame to the
584 // codec for decoding the next frame.
585 if (static_cast<size_t>(i+1) < frameInfos.size()
586 && frameInfos[i+1].fRequiredFrame == i) {
587 memcpy(priorFramePixels.reset(safeSize), pixels.get(), safeSize);
588 cachedFrame = i;
589 }
590
591 SkAutoCanvasRestore acr(canvas, true);
592 const int xTranslate = (i % factor) * decodeInfo.width();
593 const int yTranslate = (i / factor) * decodeInfo.height();
594 canvas->translate(SkIntToScalar(xTranslate), SkIntToScalar(yTranslate));
595 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
596 if (result != SkCodec::kSuccess) {
597 return Result::Ok();
598 }
599 break;
600 }
602 if (i > 0 && (decodeInfo.colorType() == kRGB_565_SkColorType)) {
603 return Result::Skip(
604 "Cannot decode frame %i to 565 (%s).", i, fPath.c_str());
605 }
606 [[fallthrough]];
607 default:
608 return Result::Fatal(
609 "Couldn't getPixels for frame %i in %s.", i, fPath.c_str());
610 }
611 }
612 break;
613 }
615 case kCodec_Mode: {
616 switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
618 // We consider these to be valid, since we should still decode what is
619 // available.
622 break;
623 default:
624 // Everything else is considered a failure.
625 return Result::Fatal("Couldn't getPixels %s.", fPath.c_str());
626 }
627
628 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
629 break;
630 }
631 case kScanline_Mode: {
632 void* dst = pixels.get();
633 uint32_t height = decodeInfo.height();
634 const bool useIncremental = [this]() {
635 auto exts = { "png", "PNG", "gif", "GIF" };
636 for (auto ext : exts) {
637 if (fPath.endsWith(ext)) {
638 return true;
639 }
640 }
641 return false;
642 }();
643 // ico may use the old scanline method or the new one, depending on whether it
644 // internally holds a bmp or a png.
645 const bool ico = fPath.endsWith("ico");
646 bool useOldScanlineMethod = !useIncremental && !ico;
647 if (useIncremental || ico) {
648 if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInfo, dst,
649 rowBytes, &options)) {
650 int rowsDecoded;
651 auto result = codec->incrementalDecode(&rowsDecoded);
653 codec->fillIncompleteImage(decodeInfo, dst, rowBytes,
655 rowsDecoded);
656 }
657 } else {
658 if (useIncremental) {
659 // Error: These should support incremental decode.
660 return Result::Fatal("Could not start incremental decode");
661 }
662 // Otherwise, this is an ICO. Since incremental failed, it must contain a BMP,
663 // which should work via startScanlineDecode
664 useOldScanlineMethod = true;
665 }
666 }
667
668 if (useOldScanlineMethod) {
669 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)) {
670 return Result::Fatal("Could not start scanline decoder");
671 }
672
673 // We do not need to check the return value. On an incomplete
674 // image, memory will be filled with a default value.
675 codec->getScanlines(dst, height, rowBytes);
676 }
677
678 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType);
679 break;
680 }
681 case kStripe_Mode: {
682 const int height = decodeInfo.height();
683 // This value is chosen arbitrarily. We exercise more cases by choosing a value that
684 // does not align with image blocks.
685 const int stripeHeight = 37;
686 const int numStripes = (height + stripeHeight - 1) / stripeHeight;
687 void* dst = pixels.get();
688
689 // Decode odd stripes
690 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) {
691 return Result::Fatal("Could not start scanline decoder");
692 }
693
694 // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
695 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
696 // to run this test for image types that do not have this scanline ordering.
697 // We only run this on Jpeg, which is always kTopDown.
698 SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder());
699
700 for (int i = 0; i < numStripes; i += 2) {
701 // Skip a stripe
702 const int linesToSkip = std::min(stripeHeight, height - i * stripeHeight);
703 codec->skipScanlines(linesToSkip);
704
705 // Read a stripe
706 const int startY = (i + 1) * stripeHeight;
707 const int linesToRead = std::min(stripeHeight, height - startY);
708 if (linesToRead > 0) {
709 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
710 rowBytes);
711 }
712 }
713
714 // Decode even stripes
715 const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo);
716 if (SkCodec::kSuccess != startResult) {
717 return Result::Fatal("Failed to restart scanline decoder with same parameters.");
718 }
719 for (int i = 0; i < numStripes; i += 2) {
720 // Read a stripe
721 const int startY = i * stripeHeight;
722 const int linesToRead = std::min(stripeHeight, height - startY);
723 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
724 rowBytes);
725
726 // Skip a stripe
727 const int linesToSkip = std::min(stripeHeight, height - (i + 1) * stripeHeight);
728 if (linesToSkip > 0) {
729 codec->skipScanlines(linesToSkip);
730 }
731 }
732
733 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType);
734 break;
735 }
737 const int width = decodeInfo.width();
738 const int height = decodeInfo.height();
739 // This value is chosen because, as we move across the image, it will sometimes
740 // align with the jpeg block sizes and it will sometimes not. This allows us
741 // to test interestingly different code paths in the implementation.
742 const int tileSize = 36;
743 SkIRect subset;
744 for (int x = 0; x < width; x += tileSize) {
745 subset = SkIRect::MakeXYWH(x, 0, std::min(tileSize, width - x), height);
746 options.fSubset = &subset;
747 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) {
748 return Result::Fatal("Could not start scanline decoder.");
749 }
750
751 codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), height, rowBytes);
752 }
753
754 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
755 break;
756 }
757 case kSubset_Mode: {
758 // Arbitrarily choose a divisor.
759 int divisor = 2;
760 // Total width/height of the image.
761 const int W = codec->getInfo().width();
762 const int H = codec->getInfo().height();
763 if (divisor > W || divisor > H) {
764 return Result::Skip("Cannot codec subset: divisor %d is too big "
765 "for %s with dimensions (%d x %d)", divisor,
766 fPath.c_str(), W, H);
767 }
768 // subset dimensions
769 // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
770 const int w = SkAlign2(W / divisor);
771 const int h = SkAlign2(H / divisor);
772 SkIRect subset;
773 options.fSubset = &subset;
774 SkBitmap subsetBm;
775 // We will reuse pixel memory from bitmap.
776 void* dst = pixels.get();
777 // Keep track of left and top (for drawing subsetBm into canvas). We could use
778 // fScale * x and fScale * y, but we want integers such that the next subset will start
779 // where the last one ended. So we'll add decodeInfo.width() and height().
780 int left = 0;
781 for (int x = 0; x < W; x += w) {
782 int top = 0;
783 for (int y = 0; y < H; y+= h) {
784 // Do not make the subset go off the edge of the image.
785 const int preScaleW = std::min(w, W - x);
786 const int preScaleH = std::min(h, H - y);
787 subset.setXYWH(x, y, preScaleW, preScaleH);
788 // And scale
789 // FIXME: Should we have a version of getScaledDimensions that takes a subset
790 // into account?
791 const int scaledW = std::max(1, SkScalarRoundToInt(preScaleW * fScale));
792 const int scaledH = std::max(1, SkScalarRoundToInt(preScaleH * fScale));
793 decodeInfo = decodeInfo.makeWH(scaledW, scaledH);
794 SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, scaledH);
795 size_t subsetRowBytes = subsetBitmapInfo.minRowBytes();
796 const SkCodec::Result result = codec->getPixels(decodeInfo, dst, subsetRowBytes,
797 &options);
798 switch (result) {
802 break;
803 default:
804 return Result::Fatal("subset codec failed to decode (%d, %d, %d, %d) "
805 "from %s with dimensions (%d x %d)\t error %d",
806 x, y, decodeInfo.width(), decodeInfo.height(),
807 fPath.c_str(), W, H, result);
808 }
809 draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes, fDstColorType,
811
812 // translate by the scaled height.
813 top += decodeInfo.height();
814 }
815 // translate by the scaled width.
816 left += decodeInfo.width();
817 }
818 return Result::Ok();
819 }
820 default:
821 SkASSERT(false);
822 return Result::Fatal("Invalid fMode");
823 }
824 return Result::Ok();
825}
const char * options
static constexpr T SkAlign2(T x)
Definition SkAlign.h:15
#define SkASSERT(cond)
Definition SkAssert.h:116
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition SkColorType.h:26
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition SkColorType.h:22
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
#define sk_float_ceil2int(x)
static bool left(const SkPoint &p0, const SkPoint &p1)
#define SkScalarRoundToInt(x)
Definition SkScalar.h:37
#define SkIntToScalar(x)
Definition SkScalar.h:57
#define W
Definition aaa.cpp:17
SkISize size() const override
static Result Ok()
Definition DMSrcSink.h:50
static std::unique_ptr< SkAndroidCodec > MakeFromData(sk_sp< SkData >, SkPngChunkReader *=nullptr)
void * reset(size_t size=0, OnShrink shrink=kAlloc_OnShrink)
void * get()
void translate(SkScalar dx, SkScalar dy)
SkImageInfo imageInfo() const
static std::unique_ptr< SkCodec > MakeFromData(sk_sp< SkData >, SkSpan< const SkCodecs::Decoder > decoders, SkPngChunkReader *=nullptr)
Definition SkCodec.cpp:241
@ kYes_ZeroInitialized
Definition SkCodec.h:308
@ kNo_ZeroInitialized
Definition SkCodec.h:315
@ kTopDown_SkScanlineOrder
Definition SkCodec.h:581
@ kInvalidConversion
Definition SkCodec.h:96
@ kIncompleteInput
Definition SkCodec.h:84
@ kInvalidInput
Definition SkCodec.h:109
@ kSuccess
Definition SkCodec.h:80
@ kErrorInInput
Definition SkCodec.h:91
static constexpr int kNoFrame
Definition SkCodec.h:650
static sk_sp< SkData > MakeFromFileName(const char path[])
Definition SkData.cpp:148
bool endsWith(const char suffixStr[]) const
Definition SkString.h:146
const char * c_str() const
Definition SkString.h:133
GAsyncResult * result
double y
double x
static void draw_to_canvas(SkCanvas *canvas, const SkImageInfo &info, void *pixels, size_t rowBytes, CodecSrc::DstColorType dstColorType, SkScalar left=0, SkScalar top=0)
static void set_bitmap_color_space(SkImageInfo *info)
static bool get_decode_info(SkImageInfo *decodeInfo, SkColorType canvasColorType, CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType)
dst
Definition cp.py:12
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition SkVx.h:706
SkScalar w
SkScalar h
int32_t height
int32_t width
Definition SkMD5.cpp:130
void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height)
Definition SkRect.h:268
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
constexpr int32_t width() const
Definition SkSize.h:36
constexpr int32_t height() const
Definition SkSize.h:37
SkImageInfo makeWH(int newWidth, int newHeight) const
size_t minRowBytes() const
size_t computeByteSize(size_t rowBytes) const
SkImageInfo makeDimensions(SkISize newSize) const
int bytesPerPixel() const
SkISize dimensions() const
int width() const
SkColorType colorType() const
int height() const
SkImageInfo makeColorType(SkColorType newColorType) const

◆ name()

Name DM::CodecSrc::name ( ) const
overridevirtual

Implements DM::Src.

Definition at line 852 of file DMSrcSink.cpp.

852 {
854 if (fMode == kAnimated_Mode) {
855 name.append("_animated");
856 }
857 if (1.0f == fScale) {
858 return name;
859 }
860 return get_scaled_name(name.c_str(), fScale);
861}
Name name() const override
static SkString Basename(const char *fullPath)
Definition SkOSPath.cpp:23
void append(const char text[])
Definition SkString.h:203
ImplicitString Name
Definition DMSrcSink.h:38
static SkString get_scaled_name(const Path &path, float scale)

◆ serial()

bool DM::CodecSrc::serial ( ) const
inlineoverridevirtual

Reimplemented from DM::Src.

Definition at line 177 of file DMSrcSink.h.

177{ return fRunSerially; }

◆ size()

SkISize DM::CodecSrc::size ( ) const
overridevirtual

Implements DM::Src.

Definition at line 827 of file DMSrcSink.cpp.

827 {
829 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
830 if (nullptr == codec) {
831 return {0, 0};
832 }
833
834 if (fMode != kAnimated_Mode) {
835 return codec->getScaledDimensions(fScale);
836 }
837
838 // We'll draw one of each frame, so make it big enough to hold them all
839 // in a grid. The grid will be roughly square, with "factor" frames per
840 // row and up to "factor" rows.
841 const size_t count = codec->getFrameInfo().size();
842 const float root = sqrt((float) count);
843 const int factor = sk_float_ceil2int(root);
844
845 auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec));
846 auto imageSize = androidCodec->getSampledDimensions(1 / fScale);
847 imageSize.fWidth = imageSize.fWidth * factor;
848 imageSize.fHeight = imageSize.fHeight * sk_float_ceil2int((float) count / (float) factor);
849 return imageSize;
850}
int count
static std::unique_ptr< SkAndroidCodec > MakeFromCodec(std::unique_ptr< SkCodec >)

◆ veto()

bool DM::CodecSrc::veto ( SinkFlags  flags) const
overridevirtual

Reimplemented from DM::Src.

Definition at line 405 of file DMSrcSink.cpp.

405 {
406 // Test to direct raster backends (8888 and 565).
407 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
408}
FlutterSemanticsFlag flags

The documentation for this class was generated from the following files: