aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar scroggo <scroggo@chromium.org>2016-11-01 08:28:28 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-11-01 08:28:28 -0700
commite71b1a1496738ebce4a8cac4ffa5ee1413996542 (patch)
tree725838575056d43c89536794e9e4f0c8c063f749
parentc25c5d73e9f4d840dc758c399496d5690709ad58 (diff)
Report repetition count in SkCodec
Add a new accessor to retrieve the repetition count. Remove constants (and corresponding copyright) in SkCodecAnimation. These may make sense for the calling code, but are not needed here. kRepetitionCountInfinite corresponds to Blink's kAnimationLoopInfinite. Move cLoopCountNotSeen to private. It is used to determine whether we still need to parse. Add a new enum to the parse query - only parse enough to determine the repetition count. Unlike Chromium, SkGifCodec does not account for deleting the reader (which SkGifCodec does not do) or failed decodes. Add a test. GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2447863002 Review-Url: https://codereview.chromium.org/2447863002
-rw-r--r--include/codec/SkCodec.h23
-rw-r--r--resources/colorTables.gifbin2829 -> 2829 bytes
-rw-r--r--src/codec/SkCodecAnimation.h44
-rw-r--r--src/codec/SkGifCodec.cpp5
-rw-r--r--src/codec/SkGifCodec.h1
-rw-r--r--tests/CodecAnimTest.cpp32
-rw-r--r--third_party/gif/SkGifImageReader.cpp12
-rw-r--r--third_party/gif/SkGifImageReader.h13
8 files changed, 68 insertions, 62 deletions
diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h
index c2519cb840..f2a717c716 100644
--- a/include/codec/SkCodec.h
+++ b/include/codec/SkCodec.h
@@ -607,8 +607,8 @@ public:
/**
* Return info about the frames in the image.
*
- * May require reading through the stream to determine the number of
- * frames.
+ * May require reading through the stream to determine info about the
+ * frames (including the count).
*
* As such, future decoding calls may require a rewind.
*
@@ -618,6 +618,21 @@ public:
return this->onGetFrameInfo();
}
+ static constexpr int kRepetitionCountInfinite = -1;
+
+ /**
+ * Return the number of times to repeat, if this image is animated.
+ *
+ * May require reading the stream to find the repetition count.
+ *
+ * As such, future decoding calls may require a rewind.
+ *
+ * For single-frame images, this will return 0.
+ */
+ int getRepetitionCount() {
+ return this->onGetRepetitionCount();
+ }
+
protected:
/**
* Takes ownership of SkStream*
@@ -766,6 +781,10 @@ protected:
return {};
}
+ virtual int onGetRepetitionCount() {
+ return 0;
+ }
+
/**
* Used for testing with qcms.
* FIXME: Remove this when we are done comparing with qcms.
diff --git a/resources/colorTables.gif b/resources/colorTables.gif
index f25d13cfaa..cefd4120dd 100644
--- a/resources/colorTables.gif
+++ b/resources/colorTables.gif
Binary files differ
diff --git a/src/codec/SkCodecAnimation.h b/src/codec/SkCodecAnimation.h
index d3fc553514..b0495b89ee 100644
--- a/src/codec/SkCodecAnimation.h
+++ b/src/codec/SkCodecAnimation.h
@@ -5,31 +5,6 @@
* found in the LICENSE file.
*/
-/*
- * Copyright (C) 2015 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
#ifndef SkCodecAnimation_DEFINED
#define SkCodecAnimation_DEFINED
@@ -38,25 +13,6 @@
class SkCodecAnimation {
public:
-
- // GIF and WebP support animation. The explanation below is in terms of GIF,
- // but the same constants are used for WebP, too.
- // GIFs have an optional 16-bit unsigned loop count that describes how an
- // animated GIF should be cycled. If the loop count is absent, the animation
- // cycles once; if it is 0, the animation cycles infinitely; otherwise the
- // animation plays n + 1 cycles (where n is the specified loop count). If the
- // GIF decoder defaults to kAnimationLoopOnce in the absence of any loop count
- // and translates an explicit "0" loop count to kAnimationLoopInfinite, then we
- // get a couple of nice side effects:
- // * By making kAnimationLoopOnce be 0, we allow the animation cycling code to
- // avoid special-casing it, and simply treat all non-negative loop counts
- // identically.
- // * By making the other two constants negative, we avoid conflicts with any
- // real loop count values.
- static const int kAnimationLoopOnce = 0;
- static const int kAnimationLoopInfinite = -1;
- static const int kAnimationNone = -2;
-
/**
* This specifies how the next frame is based on this frame.
*
diff --git a/src/codec/SkGifCodec.cpp b/src/codec/SkGifCodec.cpp
index 13223960c8..277da03191 100644
--- a/src/codec/SkGifCodec.cpp
+++ b/src/codec/SkGifCodec.cpp
@@ -139,6 +139,11 @@ std::vector<SkCodec::FrameInfo> SkGifCodec::onGetFrameInfo() {
return result;
}
+int SkGifCodec::onGetRepetitionCount() {
+ fReader->parse(SkGifImageReader::SkGIFLoopCountQuery);
+ return fReader->loopCount();
+}
+
void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, size_t frameIndex) {
fCurrColorTable = fReader->getColorTable(dstInfo.colorType(), frameIndex);
fCurrColorTableIsReal = fCurrColorTable;
diff --git a/src/codec/SkGifCodec.h b/src/codec/SkGifCodec.h
index 9d8e0e46bf..5793766204 100644
--- a/src/codec/SkGifCodec.h
+++ b/src/codec/SkGifCodec.h
@@ -49,6 +49,7 @@ protected:
uint64_t onGetFillValue(const SkImageInfo&) const override;
std::vector<FrameInfo> onGetFrameInfo() override;
+ int onGetRepetitionCount() override;
Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t,
const SkCodec::Options&, SkPMColor*, int*) override;
diff --git a/tests/CodecAnimTest.cpp b/tests/CodecAnimTest.cpp
index de36ce65d0..762cd477a7 100644
--- a/tests/CodecAnimTest.cpp
+++ b/tests/CodecAnimTest.cpp
@@ -25,21 +25,23 @@ DEF_TEST(Codec_frames, r) {
// The size of this one should match fFrameCount for animated, empty
// otherwise.
std::vector<size_t> fDurations;
+ int fRepetitionCount;
} gRecs[] = {
- { "box.gif", 1, {}, {} },
- { "color_wheel.gif", 1, {}, {} },
- { "test640x479.gif", 4, { 0, 1, 2 }, { 200, 200, 200, 200 } },
- { "colorTables.gif", 2, { 0 }, { 1000, 1000 } },
-
- { "arrow.png", 1, {}, {} },
- { "google_chrome.ico", 1, {}, {} },
- { "brickwork-texture.jpg", 1, {}, {} },
+ { "box.gif", 1, {}, {}, 0 },
+ { "color_wheel.gif", 1, {}, {}, 0 },
+ { "test640x479.gif", 4, { 0, 1, 2 }, { 200, 200, 200, 200 },
+ SkCodec::kRepetitionCountInfinite },
+ { "colorTables.gif", 2, { 0 }, { 1000, 1000 }, 5 },
+
+ { "arrow.png", 1, {}, {}, 0 },
+ { "google_chrome.ico", 1, {}, {}, 0 },
+ { "brickwork-texture.jpg", 1, {}, {}, 0 },
#if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
- { "dng_with_preview.dng", 1, {}, {} },
+ { "dng_with_preview.dng", 1, {}, {}, 0 },
#endif
- { "mandrill.wbmp", 1, {}, {} },
- { "randPixels.bmp", 1, {}, {} },
- { "yellow_rose.webp", 1, {}, {} },
+ { "mandrill.wbmp", 1, {}, {}, 0 },
+ { "randPixels.bmp", 1, {}, {}, 0 },
+ { "yellow_rose.webp", 1, {}, {}, 0 },
};
for (auto rec : gRecs) {
@@ -57,6 +59,12 @@ DEF_TEST(Codec_frames, r) {
continue;
}
+ const int repetitionCount = codec->getRepetitionCount();
+ if (repetitionCount != rec.fRepetitionCount) {
+ ERRORF(r, "%s repetition count does not match! expected: %i\tactual: %i",
+ rec.fName, rec.fRepetitionCount, repetitionCount);
+ }
+
const size_t expected = rec.fFrameCount;
const auto frameInfos = codec->getFrameInfo();
// getFrameInfo returns empty set for non-animated.
diff --git a/third_party/gif/SkGifImageReader.cpp b/third_party/gif/SkGifImageReader.cpp
index bbf5f9a2f0..0ffc7ca72a 100644
--- a/third_party/gif/SkGifImageReader.cpp
+++ b/third_party/gif/SkGifImageReader.cpp
@@ -415,6 +415,11 @@ bool SkGifImageReader::parse(SkGifImageReader::SkGIFParseQuery query)
return true;
}
+ if (SkGIFLoopCountQuery == query && m_loopCount != cLoopCountNotSeen) {
+ // Loop count has already been parsed.
+ return true;
+ }
+
// SkGIFSizeQuery and SkGIFFrameCountQuery are negative, so this is only meaningful when >= 0.
const int lastFrameToParse = (int) query;
if (lastFrameToParse >= 0 && (int) m_frames.size() > lastFrameToParse
@@ -664,9 +669,14 @@ bool SkGifImageReader::parse(SkGifImageReader::SkGIFParseQuery query)
// Zero loop count is infinite animation loop request.
if (!m_loopCount)
- m_loopCount = SkCodecAnimation::kAnimationLoopInfinite;
+ m_loopCount = SkCodec::kRepetitionCountInfinite;
GETN(1, SkGIFNetscapeExtensionBlock);
+
+ if (SkGIFLoopCountQuery == query) {
+ m_streamBuffer.flush();
+ return true;
+ }
} else if (netscapeExtension == 2) {
// Wait for specified # of bytes to enter buffer.
diff --git a/third_party/gif/SkGifImageReader.h b/third_party/gif/SkGifImageReader.h
index 5936350681..2b1b2d9423 100644
--- a/third_party/gif/SkGifImageReader.h
+++ b/third_party/gif/SkGifImageReader.h
@@ -298,8 +298,6 @@ public:
{
}
- static constexpr int cLoopCountNotSeen = -2;
-
~SkGifImageReader()
{
}
@@ -317,6 +315,8 @@ public:
SkGIFSizeQuery = -1,
// Parse to the end, so we know about all frames.
SkGIFFrameCountQuery = -2,
+ // Parse until we see the loop count.
+ SkGIFLoopCountQuery = -3,
};
// Parse incoming GIF data stream into internal data structures.
@@ -340,7 +340,12 @@ public:
// FIXME: This extra complexity is not necessary and we should just report m_frames.size().
return m_frames.back()->isHeaderDefined() ? m_frames.size() : m_frames.size() - 1;
}
- int loopCount() const { return m_loopCount; }
+ int loopCount() const {
+ if (cLoopCountNotSeen == m_loopCount) {
+ return 0;
+ }
+ return m_loopCount;
+ }
const SkGIFColorMap& globalColorMap() const
{
@@ -389,6 +394,8 @@ private:
unsigned m_screenWidth; // Logical screen width & height.
unsigned m_screenHeight;
SkGIFColorMap m_globalColorMap;
+
+ static constexpr int cLoopCountNotSeen = -2;
int m_loopCount; // Netscape specific extension block to control the number of animation loops a GIF renders.
std::vector<std::unique_ptr<SkGIFFrameContext>> m_frames;