Properly zero in webp if no prior frame
When erasing the prior frame rect, we need to update the frame rect to take scaling into account. We already do if the prior frame was provided; also do so if it was not provided. Note that this only affects an image with a restore previous frame that is being scaled. webp does not support restore previous, so this will not affect AnimatedImageDrawable in Android. Change-Id: I2d9a4ad45262a0e7afd1134958aff5c6e2ca6687 Reviewed-on: https://skia-review.googlesource.com/115646 Reviewed-by: Derek Sollenberger <djsollen@google.com> Commit-Queue: Leon Scroggins <scroggo@google.com>
This commit is contained in:
parent
a0047bcff7
commit
7916c0ec35
@ -208,16 +208,37 @@ bool SkCodec::rewindIfNeeded() {
|
||||
return this->onRewind();
|
||||
}
|
||||
|
||||
static void zero_rect(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes,
|
||||
SkIRect frameRect) {
|
||||
if (!frameRect.intersect(dstInfo.bounds())) {
|
||||
return;
|
||||
bool zero_rect(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes,
|
||||
SkISize srcDimensions, SkIRect prevRect) {
|
||||
const auto dimensions = dstInfo.dimensions();
|
||||
if (dimensions != srcDimensions) {
|
||||
SkRect src = SkRect::Make(srcDimensions);
|
||||
SkRect dst = SkRect::Make(dimensions);
|
||||
SkMatrix map = SkMatrix::MakeRectToRect(src, dst, SkMatrix::kCenter_ScaleToFit);
|
||||
SkRect asRect = SkRect::Make(prevRect);
|
||||
if (!map.mapRect(&asRect)) {
|
||||
return false;
|
||||
}
|
||||
asRect.roundIn(&prevRect);
|
||||
if (prevRect.isEmpty()) {
|
||||
// Down-scaling shrank the empty portion to nothing,
|
||||
// so nothing to zero.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const auto info = dstInfo.makeWH(frameRect.width(), frameRect.height());
|
||||
|
||||
if (!prevRect.intersect(dstInfo.bounds())) {
|
||||
SkCodecPrintf("rectangles do not intersect!");
|
||||
SkASSERT(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
const SkImageInfo info = dstInfo.makeWH(prevRect.width(), prevRect.height());
|
||||
const size_t bpp = dstInfo.bytesPerPixel();
|
||||
const size_t offset = frameRect.x() * bpp + frameRect.y() * rowBytes;
|
||||
auto* eraseDst = SkTAddOffset<void>(pixels, offset);
|
||||
const size_t offset = prevRect.x() * bpp + prevRect.y() * rowBytes;
|
||||
void* eraseDst = SkTAddOffset<void>(pixels, offset);
|
||||
SkSampler::Fill(info, eraseDst, rowBytes, 0, SkCodec::kNo_ZeroInitialized);
|
||||
return true;
|
||||
}
|
||||
|
||||
SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels, size_t rowBytes,
|
||||
@ -276,28 +297,9 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels,
|
||||
// need to clear, since it must be covered by the desired frame.
|
||||
if (options.fPriorFrame == requiredFrame) {
|
||||
SkIRect prevRect = prevFrame->frameRect();
|
||||
if (info.dimensions() != fSrcInfo.dimensions()) {
|
||||
auto src = SkRect::Make(fSrcInfo.dimensions());
|
||||
auto dst = SkRect::Make(info.dimensions());
|
||||
SkMatrix map = SkMatrix::MakeRectToRect(src, dst,
|
||||
SkMatrix::kCenter_ScaleToFit);
|
||||
SkRect asRect = SkRect::Make(prevRect);
|
||||
if (!map.mapRect(&asRect)) {
|
||||
return kInternalError;
|
||||
}
|
||||
asRect.roundIn(&prevRect);
|
||||
if (prevRect.isEmpty()) {
|
||||
// Down-scaling shrank the empty portion to nothing,
|
||||
// so nothing to zero.
|
||||
break;
|
||||
}
|
||||
if (!prevRect.intersect(SkIRect::MakeSize(info.dimensions()))) {
|
||||
SkCodecPrintf("rectangles do not intersect!");
|
||||
SkASSERT(false);
|
||||
break;
|
||||
}
|
||||
if (!zero_rect(info, pixels, rowBytes, fSrcInfo.dimensions(), prevRect)) {
|
||||
return kInternalError;
|
||||
}
|
||||
zero_rect(info, pixels, rowBytes, prevRect);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -314,7 +316,10 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels,
|
||||
const auto* prevFrame = frameHolder->getFrame(requiredFrame);
|
||||
const auto disposalMethod = prevFrame->getDisposalMethod();
|
||||
if (disposalMethod == SkCodecAnimation::DisposalMethod::kRestoreBGColor) {
|
||||
zero_rect(info, pixels, rowBytes, prevFrame->frameRect());
|
||||
auto prevRect = prevFrame->frameRect();
|
||||
if (!zero_rect(info, pixels, rowBytes, fSrcInfo.dimensions(), prevRect)) {
|
||||
return kInternalError;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -422,9 +422,27 @@ DEF_TEST(AndroidCodec_animated, r) {
|
||||
options.fPriorFrame = i - 1;
|
||||
info = info.makeAlphaType(frameInfo.fAlphaType);
|
||||
|
||||
const auto result = codec->codec()->getPixels(info, bm.getPixels(), bm.rowBytes(),
|
||||
&options);
|
||||
auto result = codec->codec()->getPixels(info, bm.getPixels(), bm.rowBytes(),
|
||||
&options);
|
||||
REPORTER_ASSERT(r, result == SkCodec::kSuccess);
|
||||
|
||||
// Now compare to not using prior frame.
|
||||
SkBitmap bm2;
|
||||
bm2.allocPixels(info);
|
||||
|
||||
options.fPriorFrame = SkCodec::kNone;
|
||||
result = codec->codec()->getPixels(info, bm2.getPixels(), bm2.rowBytes(),
|
||||
&options);
|
||||
REPORTER_ASSERT(r, result == SkCodec::kSuccess);
|
||||
|
||||
for (int y = 0; y < info.height(); ++y) {
|
||||
if (memcmp(bm.getAddr32(0, y), bm2.getAddr32(0, y), info.minRowBytes())) {
|
||||
ERRORF(r, "pixel mismatch for sample size %i, frame %i resulting in "
|
||||
"dimensions %i x %i line %i\n",
|
||||
sampleSize, i, info.width(), info.height(), y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user