diff options
Diffstat (limited to 'src/android')
-rw-r--r-- | src/android/SkAnimatedImage.cpp | 120 |
1 files changed, 73 insertions, 47 deletions
diff --git a/src/android/SkAnimatedImage.cpp b/src/android/SkAnimatedImage.cpp index de25f309e4..daeec81256 100644 --- a/src/android/SkAnimatedImage.cpp +++ b/src/android/SkAnimatedImage.cpp @@ -10,8 +10,10 @@ #include "SkCanvas.h" #include "SkCodec.h" #include "SkCodecPriv.h" +#include "SkImagePriv.h" #include "SkPicture.h" #include "SkPictureRecorder.h" +#include "SkPixelRef.h" sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> codec, SkISize scaledSize, SkIRect cropRect, sk_sp<SkPicture> postProcess) { @@ -30,7 +32,7 @@ sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> cod auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize, decodeInfo, cropRect, std::move(postProcess))); - if (!image->fActiveFrame.fBitmap.getPixels()) { + if (!image->fDisplayFrame.fBitmap.getPixels()) { // tryAllocPixels failed. return nullptr; } @@ -49,7 +51,7 @@ sk_sp<SkAnimatedImage> SkAnimatedImage::Make(std::unique_ptr<SkAndroidCodec> cod auto image = sk_sp<SkAnimatedImage>(new SkAnimatedImage(std::move(codec), scaledSize, decodeInfo, cropRect, nullptr)); - if (!image->fActiveFrame.fBitmap.getPixels()) { + if (!image->fDisplayFrame.fBitmap.getPixels()) { // tryAllocPixels failed. return nullptr; } @@ -72,7 +74,7 @@ SkAnimatedImage::SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec, SkISize , fRepetitionCount(fCodec->codec()->getRepetitionCount()) , fRepetitionsCompleted(0) { - if (!fActiveFrame.fBitmap.tryAllocPixels(fDecodeInfo)) { + if (!fDecodingFrame.fBitmap.tryAllocPixels(fDecodeInfo)) { return; } @@ -95,10 +97,33 @@ SkAnimatedImage::Frame::Frame() : fIndex(SkCodec::kNone) {} +bool SkAnimatedImage::Frame::init(const SkImageInfo& info, OnInit onInit) { + if (fBitmap.getPixels()) { + if (fBitmap.pixelRef()->unique()) { + SkAssertResult(fBitmap.setAlphaType(info.alphaType())); + return true; + } + + // An SkCanvas provided to onDraw is still holding a reference. + // Copy before we decode to ensure that we don't overwrite the + // expected contents of the image. + if (OnInit::kRestoreIfNecessary == onInit) { + SkBitmap tmp; + if (!tmp.tryAllocPixels(info)) { + return false; + } + + memcpy(tmp.getPixels(), fBitmap.getPixels(), fBitmap.computeByteSize()); + SkTSwap(tmp, fBitmap); + return true; + } + } + + return fBitmap.tryAllocPixels(info); +} + bool SkAnimatedImage::Frame::copyTo(Frame* dst) const { - if (dst->fBitmap.getPixels()) { - dst->fBitmap.setAlphaType(fBitmap.alphaType()); - } else if (!dst->fBitmap.tryAllocPixels(fBitmap.info())) { + if (!dst->init(fBitmap.info(), OnInit::kNoRestore)) { return false; } @@ -111,19 +136,10 @@ bool SkAnimatedImage::Frame::copyTo(Frame* dst) const { void SkAnimatedImage::reset() { fFinished = false; fRepetitionsCompleted = 0; - if (fActiveFrame.fIndex == 0) { - // Already showing the first frame. - return; + if (fDisplayFrame.fIndex != 0) { + fDisplayFrame.fIndex = SkCodec::kNone; + this->decodeNextFrame(); } - - if (fRestoreFrame.fIndex == 0) { - SkTSwap(fActiveFrame, fRestoreFrame); - // Now we're showing the first frame. - return; - } - - fActiveFrame.fIndex = SkCodec::kNone; - this->decodeNextFrame(); } static bool is_restore_previous(SkCodecAnimation::DisposalMethod dispose) { @@ -160,7 +176,7 @@ int SkAnimatedImage::decodeNextFrame() { } bool animationEnded = false; - int frameToDecode = this->computeNextFrame(fActiveFrame.fIndex, &animationEnded); + int frameToDecode = this->computeNextFrame(fDisplayFrame.fIndex, &animationEnded); SkCodec::FrameInfo frameInfo; if (fCodec->codec()->getFrameInfo(frameToDecode, &frameInfo)) { @@ -188,19 +204,21 @@ int SkAnimatedImage::decodeNextFrame() { } } - if (frameToDecode == fActiveFrame.fIndex) { + if (frameToDecode == fDisplayFrame.fIndex) { if (animationEnded) { return this->finish(); } return fCurrentFrameDuration; } - if (frameToDecode == fRestoreFrame.fIndex) { - SkTSwap(fActiveFrame, fRestoreFrame); - if (animationEnded) { - return this->finish(); + for (Frame* frame : { &fRestoreFrame, &fDecodingFrame }) { + if (frameToDecode == frame->fIndex) { + SkTSwap(fDisplayFrame, *frame); + if (animationEnded) { + return this->finish(); + } + return fCurrentFrameDuration; } - return fCurrentFrameDuration; } // The following code makes an effort to avoid overwriting a frame that will @@ -216,9 +234,9 @@ int SkAnimatedImage::decodeNextFrame() { // frameToDecode will be discarded immediately after drawing, so // do not overwrite a frame which could possibly be used in the // future. - if (fActiveFrame.fIndex != SkCodec::kNone && - !is_restore_previous(fActiveFrame.fDisposalMethod)) { - SkTSwap(fActiveFrame, fRestoreFrame); + if (fDecodingFrame.fIndex != SkCodec::kNone && + !is_restore_previous(fDecodingFrame.fDisposalMethod)) { + SkTSwap(fDecodingFrame, fRestoreFrame); } } } else { @@ -229,34 +247,36 @@ int SkAnimatedImage::decodeNextFrame() { return frame.fIndex >= frameInfo.fRequiredFrame && frame.fIndex < frameToDecode; }; - if (validPriorFrame(fActiveFrame)) { + if (validPriorFrame(fDecodingFrame)) { if (is_restore_previous(frameInfo.fDisposalMethod)) { - // fActiveFrame is a good frame to use for this one, but we + // fDecodingFrame is a good frame to use for this one, but we // don't want to overwrite it. - fActiveFrame.copyTo(&fRestoreFrame); + fDecodingFrame.copyTo(&fRestoreFrame); + } + options.fPriorFrame = fDecodingFrame.fIndex; + } else if (validPriorFrame(fDisplayFrame)) { + if (!fDisplayFrame.copyTo(&fDecodingFrame)) { + SkCodecPrintf("Failed to allocate pixels for frame\n"); + return this->finish(); } - options.fPriorFrame = fActiveFrame.fIndex; + options.fPriorFrame = fDecodingFrame.fIndex; } else if (validPriorFrame(fRestoreFrame)) { if (!is_restore_previous(frameInfo.fDisposalMethod)) { - SkTSwap(fActiveFrame, fRestoreFrame); - } else if (!fRestoreFrame.copyTo(&fActiveFrame)) { + SkTSwap(fDecodingFrame, fRestoreFrame); + } else if (!fRestoreFrame.copyTo(&fDecodingFrame)) { SkCodecPrintf("Failed to restore frame\n"); return this->finish(); } - options.fPriorFrame = fActiveFrame.fIndex; + options.fPriorFrame = fDecodingFrame.fIndex; } } auto alphaType = kOpaque_SkAlphaType == frameInfo.fAlphaType ? kOpaque_SkAlphaType : kPremul_SkAlphaType; - SkBitmap* dst = &fActiveFrame.fBitmap; - if (dst->getPixels()) { - SkAssertResult(dst->setAlphaType(alphaType)); - } else { - auto info = fDecodeInfo.makeAlphaType(alphaType); - if (!dst->tryAllocPixels(info)) { - return this->finish(); - } + auto info = fDecodeInfo.makeAlphaType(alphaType); + SkBitmap* dst = &fDecodingFrame.fBitmap; + if (!fDecodingFrame.init(info, Frame::OnInit::kRestoreIfNecessary)) { + return this->finish(); } auto result = fCodec->codec()->getPixels(dst->info(), dst->getPixels(), dst->rowBytes(), @@ -266,8 +286,11 @@ int SkAnimatedImage::decodeNextFrame() { return this->finish(); } - fActiveFrame.fIndex = frameToDecode; - fActiveFrame.fDisposalMethod = frameInfo.fDisposalMethod; + fDecodingFrame.fIndex = frameToDecode; + fDecodingFrame.fDisposalMethod = frameInfo.fDisposalMethod; + + SkTSwap(fDecodingFrame, fDisplayFrame); + fDisplayFrame.fBitmap.notifyPixelsChanged(); if (animationEnded) { return this->finish(); @@ -276,8 +299,11 @@ int SkAnimatedImage::decodeNextFrame() { } void SkAnimatedImage::onDraw(SkCanvas* canvas) { + auto image = SkMakeImageFromRasterBitmap(fDisplayFrame.fBitmap, + kNever_SkCopyPixelsMode); + if (fSimple) { - canvas->drawBitmap(fActiveFrame.fBitmap, 0, 0); + canvas->drawImage(image, 0, 0); return; } @@ -290,7 +316,7 @@ void SkAnimatedImage::onDraw(SkCanvas* canvas) { canvas->concat(fMatrix); SkPaint paint; paint.setFilterQuality(kLow_SkFilterQuality); - canvas->drawBitmap(fActiveFrame.fBitmap, 0, 0, &paint); + canvas->drawImage(image, 0, 0, &paint); } if (fPostProcess) { canvas->drawPicture(fPostProcess); |