Index: src/3rdParty/webkit/work/WebCore/platform/graphics/BitmapImage.cpp
===================================================================
--- src.orig/3rdParty/webkit/work/WebCore/platform/graphics/BitmapImage.cpp
+++ src/3rdParty/webkit/work/WebCore/platform/graphics/BitmapImage.cpp
@@ -30,32 +30,41 @@
 #include "FloatRect.h"
 #include "ImageObserver.h"
 #include "IntRect.h"
+#include "MIMETypeRegistry.h"
 #include "PlatformString.h"
 #include "Timer.h"
+#include "SystemTime.h"
 #include <wtf/Vector.h>
-#include "MIMETypeRegistry.h"
 
 namespace WebCore {
 
 // Animated images >5MB are considered large enough that we'll only hang on to
 // one frame at a time.
 const unsigned cLargeAnimationCutoff = 5242880;
+static int frameBytes(const IntSize& frameSize)
+{
+    return frameSize.width() * frameSize.height() * 4;
+}
 
 BitmapImage::BitmapImage(ImageObserver* observer, bool accelerated)
     : Image(observer)
     , m_currentFrame(0)
     , m_frames(0)
     , m_frameTimer(0)
-    , m_repetitionCount(0)
+    , m_repetitionCount(cAnimationNone)
+    , m_repetitionCountStatus(Unknown)
     , m_repetitionsComplete(0)
+    , m_desiredFrameStartTime(0)
     , m_isSolidColor(false)
-    , m_animatingImageType(true)
+    , m_checkedForSolidColor(false)
     , m_animationFinished(false)
     , m_allDataReceived(false)
     , m_haveSize(false)
     , m_sizeAvailable(false)
     , m_decodedSize(0)
+    , m_haveFrameCount(false)
     , m_accelerated(accelerated)
+    , m_frameCount(0)
 {
     initPlatformData();
 }
@@ -99,18 +108,22 @@ void BitmapImage::destroyDecodedData(boo
     }
 }
 
+
+void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll)
+{
+    // Animated images >5MB are considered large enough that we'll only hang on
+    // to one frame at a time.
+    static const unsigned cLargeAnimationCutoff = 5242880;
+    if (frameCount() * frameBytes(m_size) > cLargeAnimationCutoff)
+        destroyDecodedData(destroyAll);
+}
+
+
 void BitmapImage::cacheFrame(size_t index)
 {
     size_t numFrames = frameCount();
     ASSERT(m_decodedSize == 0 || numFrames > 1);
     
-    if (!m_frames.size() && shouldAnimate()) {            
-        // Snag the repetition count.
-        m_repetitionCount = m_source.repetitionCount();
-        if (m_repetitionCount == cAnimationNone)
-            m_animatingImageType = false;
-    }
-    
     if (m_frames.size() < numFrames)
         m_frames.grow(numFrames);
 
@@ -118,7 +131,8 @@ void BitmapImage::cacheFrame(size_t inde
     if (numFrames == 1 && m_frames[index].m_frame)
         checkForSolidColor();
 
-    if (shouldAnimate())
+    m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index);
+    if (repetitionCount(false) != cAnimationNone)
         m_frames[index].m_duration = m_source.frameDurationAtIndex(index);
     m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index);
     
@@ -147,6 +161,9 @@ bool BitmapImage::dataChanged(bool allDa
     m_allDataReceived = allDataReceived;
     m_source.setData(m_data.get(), allDataReceived, m_accelerated);
     
+    // Clear the frame count.
+    m_haveFrameCount = false;
+
     // Image properties will not be available until the first frame of the file
     // reaches kCGImageStatusIncomplete.
     return isSizeAvailable();
@@ -154,7 +171,11 @@ bool BitmapImage::dataChanged(bool allDa
 
 size_t BitmapImage::frameCount()
 {
-    return m_source.frameCount();
+    if (!m_haveFrameCount) {
+        m_haveFrameCount = true;
+        m_frameCount = m_source.frameCount();
+    }
+    return m_frameCount;
 }
 
 bool BitmapImage::isSizeAvailable()
@@ -178,6 +199,17 @@ NativeImagePtr BitmapImage::frameAtIndex
     return m_frames[index].m_frame;
 }
 
+bool BitmapImage::frameIsCompleteAtIndex(size_t index)
+{
+    if (index >= frameCount())
+        return true;
+
+    if (index >= m_frames.size() || !m_frames[index].m_frame)
+        cacheFrame(index);
+
+    return m_frames[index].m_isComplete;
+}
+
 float BitmapImage::frameDurationAtIndex(size_t index)
 {
     if (index >= frameCount())
@@ -200,22 +232,118 @@ bool BitmapImage::frameHasAlphaAtIndex(s
     return m_frames[index].m_hasAlpha;
 }
 
+int BitmapImage::repetitionCount(bool imageKnownToBeComplete)
+{
+    if ((m_repetitionCountStatus == Unknown) || ((m_repetitionCountStatus == Uncertain) && imageKnownToBeComplete)) {
+        // Snag the repetition count.  If |imageKnownToBeComplete| is false, the
+        // repetition count may not be accurate yet for GIFs; in this case the
+        // decoder will default to cAnimationLoopOnce, and we'll try and read
+        // the count again once the whole image is decoded.
+        m_repetitionCount = m_source.repetitionCount();
+        m_repetitionCountStatus = (imageKnownToBeComplete || m_repetitionCount == cAnimationNone) ? Certain : Uncertain;
+    }
+    return m_repetitionCount;
+}
+
 bool BitmapImage::shouldAnimate()
 {
-    return (m_animatingImageType && !m_animationFinished && imageObserver());
+    return (repetitionCount(false) != cAnimationNone && !m_animationFinished && imageObserver());
 }
 
-void BitmapImage::startAnimation()
+void BitmapImage::startAnimation(bool catchUpIfNecessary)
 {
     if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
         return;
 
-    // Don't advance the animation until the current frame has completely loaded.
-    if (!m_source.frameIsCompleteAtIndex(m_currentFrame))
+    // Determine time for next frame to start.  By ignoring paint and timer lag
+    // in this calculation, we make the animation appear to run at its desired
+    // rate regardless of how fast it's being repainted.
+    const double currentDuration = frameDurationAtIndex(m_currentFrame);
+    const double time = currentTime();
+    if (m_desiredFrameStartTime == 0) {
+        m_desiredFrameStartTime = time + currentDuration;
+    } else {
+        m_desiredFrameStartTime += currentDuration;
+
+        // When an animated image is more than five minutes out of date, the
+        // user probably doesn't care about resyncing and we could burn a lot of
+        // time looping through frames below.  Just reset the timings.
+        const double cAnimationResyncCutoff = 5 * 60;
+        if ((time - m_desiredFrameStartTime) > cAnimationResyncCutoff)
+            m_desiredFrameStartTime = time + currentDuration;
+    }
+
+    // Don't advance the animation to an incomplete frame.
+    size_t nextFrame = (m_currentFrame + 1) % frameCount();
+    if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame))
+        return;
+
+    // Don't advance past the last frame if we haven't decoded the whole image
+    // yet and our repetition count is potentially unset.  The repetition count
+    // in a GIF can potentially come after all the rest of the image data, so
+    // wait on it.
+    if (!m_allDataReceived && repetitionCount(false) == cAnimationLoopOnce && m_currentFrame >= (frameCount() - 1))
         return;
 
-    m_frameTimer = new Timer<BitmapImage>(this, &BitmapImage::advanceAnimation);
-    m_frameTimer->startOneShot(frameDurationAtIndex(m_currentFrame));
+    // The image may load more slowly than it's supposed to animate, so that by
+    // the time we reach the end of the first repetition, we're well behind.
+    // Clamp the desired frame start time in this case, so that we don't skip
+    // frames (or whole iterations) trying to "catch up".  This is a tradeoff:
+    // It guarantees users see the whole animation the second time through and
+    // don't miss any repetitions, and is closer to what other browsers do; on
+    // the other hand, it makes animations "less accurate" for pages that try to
+    // sync an image and some other resource (e.g. audio), especially if users
+    // switch tabs (and thus stop drawing the animation, which will pause it)
+    // during that initial loop, then switch back later.
+    if (nextFrame == 0 && m_repetitionsComplete == 0 && m_desiredFrameStartTime < time)
+      m_desiredFrameStartTime = time;
+
+    if (!catchUpIfNecessary || time < m_desiredFrameStartTime) {
+        // Haven't yet reached time for next frame to start; delay until then.
+        m_frameTimer = new Timer<BitmapImage>(this, &BitmapImage::advanceAnimation);
+        m_frameTimer->startOneShot(std::max(m_desiredFrameStartTime - time, 0.));
+    } else {
+        // We've already reached or passed the time for the next frame to start.
+        // See if we've also passed the time for frames after that to start, in
+        // case we need to skip some frames entirely.  Remember not to advance
+        // to an incomplete frame.
+        for (size_t frameAfterNext = (nextFrame + 1) % frameCount(); frameIsCompleteAtIndex(frameAfterNext); frameAfterNext = (nextFrame + 1) % frameCount()) {
+            // Should we skip the next frame?
+            double frameAfterNextStartTime = m_desiredFrameStartTime + frameDurationAtIndex(nextFrame);
+            if (time < frameAfterNextStartTime)
+                break;
+
+            // Yes; skip over it without notifying our observers.
+            if (!internalAdvanceAnimation(true))
+                return;
+            m_desiredFrameStartTime = frameAfterNextStartTime;
+            nextFrame = frameAfterNext;
+        }
+
+        // Draw the next frame immediately.  Note that m_desiredFrameStartTime
+        // may be in the past, meaning the next time through this function we'll
+        // kick off the next advancement sooner than this frame's duration would
+        // suggest.
+        if (internalAdvanceAnimation(false)) {
+            // The image region has been marked dirty, but once we return to our
+            // caller, draw() will clear it, and nothing will cause the
+            // animation to advance again.  We need to start the timer for the
+            // next frame running, or the animation can hang.  (Compare this
+            // with when advanceAnimation() is called, and the region is dirtied
+            // while draw() is not in the callstack, meaning draw() gets called
+            // to update the region and thus startAnimation() is reached again.)
+            // NOTE: For large images with slow or heavily-loaded systems,
+            // throwing away data as we go (see destroyDecodedData()) means we
+            // can spend so much time re-decoding data above that by the time we
+            // reach here we're behind again.  If we let startAnimation() run
+            // the catch-up code again, we can get long delays without painting
+            // as we race the timer, or even infinite recursion.  In this
+            // situation the best we can do is to simply change frames as fast
+            // as possible, so force startAnimation() to set a zero-delay timer
+            // and bail out if we're not caught up.
+            startAnimation(false);
+        }
+    }
 }
 
 void BitmapImage::stopAnimation()
@@ -231,53 +359,57 @@ void BitmapImage::resetAnimation()
     stopAnimation();
     m_currentFrame = 0;
     m_repetitionsComplete = 0;
+    m_desiredFrameStartTime = 0;
     m_animationFinished = false;
-    int frameSize = m_size.width() * m_size.height() * 4;
     
     // For extremely large animations, when the animation is reset, we just throw everything away.
-    if (frameCount() * frameSize > cLargeAnimationCutoff)
-        destroyDecodedData();
+    destroyDecodedDataIfNecessary(true);
+}
+
+void BitmapImage::advanceAnimation(Timer<BitmapImage>*)
+{
+    internalAdvanceAnimation(false);
+    // At this point the image region has been marked dirty, and if it's
+    // onscreen, we'll soon make a call to draw(), which will call
+    // startAnimation() again to keep the animation moving.
 }
 
-void BitmapImage::advanceAnimation(Timer<BitmapImage>* timer)
+bool BitmapImage::internalAdvanceAnimation(bool skippingFrames)
 {
     // Stop the animation.
     stopAnimation();
     
     // See if anyone is still paying attention to this animation.  If not, we don't
     // advance and will remain suspended at the current frame until the animation is resumed.
-    if (imageObserver()->shouldPauseAnimation(this))
-        return;
+    if (!skippingFrames && imageObserver()->shouldPauseAnimation(this))
+        return false;
 
-    m_currentFrame++;
+    ++m_currentFrame;
+    bool advancedAnimation = true;
+    bool destroyAll = false;
     if (m_currentFrame >= frameCount()) {
-        m_repetitionsComplete += 1;
-        if (m_repetitionCount && m_repetitionsComplete >= m_repetitionCount) {
+        ++m_repetitionsComplete;
+
+        // Get the repetition count again.  If we weren't able to get a
+        // repetition count before, we should have decoded the whole image by
+        // now, so it should now be available.
+        if (repetitionCount(true) && m_repetitionsComplete >= m_repetitionCount) {
             m_animationFinished = true;
-            m_currentFrame--;
-            return;
+            m_desiredFrameStartTime = 0;
+            --m_currentFrame;
+            advancedAnimation = false;
+        } else {
+            m_currentFrame = 0;
+            destroyAll = true;
         }
-        m_currentFrame = 0;
     }
+    destroyDecodedDataIfNecessary(destroyAll);
 
-    // Notify our observer that the animation has advanced.
-    imageObserver()->animationAdvanced(this);
-
-    // For large animated images, go ahead and throw away frames as we go to save
-    // footprint.
-    int frameSize = m_size.width() * m_size.height() * 4;
-    if (frameCount() * frameSize > cLargeAnimationCutoff) {
-        // Destroy all of our frames and just redecode every time.
-        destroyDecodedData();
-
-        // Go ahead and decode the next frame.
-        frameAtIndex(m_currentFrame);
-    }
-    
-    // We do not advance the animation explicitly.  We rely on a subsequent draw of the image
-    // to force a request for the next frame via startAnimation().  This allows images that move offscreen while
-    // scrolling to stop animating (thus saving memory from additional decoded frames and
-    // CPU time spent doing the decoding).
+    // We need to draw this frame if we advanced to it while not skipping, or if
+    // while trying to skip frames we hit the last frame and thus had to stop.
+    if (skippingFrames != advancedAnimation)
+        imageObserver()->animationAdvanced(this);
+    return advancedAnimation;
 }
 
 }
Index: src/3rdParty/webkit/work/WebCore/platform/graphics/BitmapImage.h
===================================================================
--- src.orig/3rdParty/webkit/work/WebCore/platform/graphics/BitmapImage.h
+++ src/3rdParty/webkit/work/WebCore/platform/graphics/BitmapImage.h
@@ -66,6 +66,7 @@ template <typename T> class Timer;
 struct FrameData : Noncopyable {
     FrameData()
         : m_frame(0)
+        , m_isComplete(false)
         , m_duration(0)
         , m_hasAlpha(true) 
     {
@@ -79,6 +80,7 @@ struct FrameData : Noncopyable {
     void clear();
 
     NativeImagePtr m_frame;
+    bool m_isComplete;
     float m_duration;
     bool m_hasAlpha;
 };
@@ -96,6 +98,10 @@ public:
     BitmapImage(ImageObserver* = 0, bool accelerated = false);
     ~BitmapImage();
     
+    virtual bool isBitmapImage() const { return true; }
+
+    virtual bool hasSingleSecurityOrigin() const { return true; }
+
     virtual IntSize size() const;
     virtual bool isAccelerated() const { return m_accelerated; }
 
@@ -130,7 +136,14 @@ public:
 
     virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); }
 
-private:
+protected:
+    enum RepetitionCountStatus {
+      Unknown,    // We haven't checked the source's repetition count.
+      Uncertain,  // We have a repetition count, but it might be wrong (some GIFs have a count after the image data, and will report "loop once" until all data has been decoded).
+      Certain,    // The repetition count is known to be correct.
+    };
+
+//private:
 #if PLATFORM(WIN)
     virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator);
 #endif
@@ -142,6 +155,7 @@ private:
     size_t currentFrame() const { return m_currentFrame; }
     size_t frameCount();
     NativeImagePtr frameAtIndex(size_t);
+    bool frameIsCompleteAtIndex(size_t);
     float frameDurationAtIndex(size_t);
     bool frameHasAlphaAtIndex(size_t); 
 
@@ -151,23 +165,43 @@ private:
     // Called to invalidate all our cached data.  If an image is loading incrementally, we only
     // invalidate the last cached frame.
     virtual void destroyDecodedData(bool incremental = false);
+    // If the image is large enough, calls destroyDecodedData() and passes
+    // |destroyAll| along.
+    void destroyDecodedDataIfNecessary(bool destroyAll);
 
     // Whether or not size is available yet.    
     bool isSizeAvailable();
 
     // Animation.
+    int repetitionCount(bool imageKnownToBeComplete);  // |imageKnownToBeComplete| should be set if the caller knows the entire image has been decoded.
     bool shouldAnimate();
-    virtual void startAnimation();
+    virtual void startAnimation(bool catchUpIfNecessary = true);
     void advanceAnimation(Timer<BitmapImage>*);
-    
+
+    // Function that does the real work of advancing the animation.  When
+    // skippingFrames is true, we're in the middle of a loop trying to skip over
+    // a bunch of animation frames, so we should not do things like decode each
+    // one or notify our observers.
+    // Returns whether the animation was advanced.
+    bool internalAdvanceAnimation(bool skippingFrames);
+
     // Handle platform-specific data
     void initPlatformData();
     void invalidatePlatformData();
     
     // Checks to see if the image is a 1x1 solid color.  We optimize these images and just do a fill rect instead.
+    // This check should happen regardless whether m_checkedForSolidColor is already set, as the frame may have
+    // changed.
     void checkForSolidColor();
     
-    virtual bool mayFillWithSolidColor() const { return m_isSolidColor && m_currentFrame == 0; }
+    virtual bool mayFillWithSolidColor()
+    {
+        if (!m_checkedForSolidColor && frameCount() > 0) {
+            checkForSolidColor();
+            ASSERT(m_checkedForSolidColor);
+        }
+        return m_isSolidColor && m_currentFrame == 0;
+    }
     virtual Color solidColor() const { return m_solidColor; }
     
     ImageSource m_source;
@@ -177,8 +211,10 @@ private:
     Vector<FrameData> m_frames; // An array of the cached frames of the animation. We have to ref frames to pin them in the cache.
     
     Timer<BitmapImage>* m_frameTimer;
-    int m_repetitionCount; // How many total animation loops we should do.
+    int m_repetitionCount; // How many total animation loops we should do.  This will be cAnimationNone if this image type is incapable of animation.
+    RepetitionCountStatus m_repetitionCountStatus;
     int m_repetitionsComplete;  // How many repetitions we've finished.
+    double m_desiredFrameStartTime;  // The system time at which we hope to see the next call to startAnimation().
 
 #if PLATFORM(MAC)
     mutable RetainPtr<NSImage> m_nsImage; // A cached NSImage of frame 0. Only built lazily if someone actually queries for one.
@@ -187,8 +223,8 @@ private:
 
     Color m_solidColor;  // If we're a 1x1 solid color, this is the color to use to fill.
     bool m_isSolidColor;  // Whether or not we are a 1x1 solid image.
+    bool m_checkedForSolidColor; // Whether we've checked the frame for solid color.
 
-    bool m_animatingImageType;  // Whether or not we're an image type that is capable of animating (GIF).
     bool m_animationFinished;  // Whether or not we've completed the entire animation.
 
     bool m_allDataReceived;  // Whether or not we've received all our data.
@@ -202,6 +238,8 @@ private:
     QPixmap *m_pixmap;
 #endif
 
+    mutable bool m_haveFrameCount;
+    size_t m_frameCount;
 };
 
 }
Index: src/3rdParty/webkit/work/WebCore/platform/graphics/Image.h
===================================================================
--- src.orig/3rdParty/webkit/work/WebCore/platform/graphics/Image.h
+++ src/3rdParty/webkit/work/WebCore/platform/graphics/Image.h
@@ -102,9 +102,9 @@ public:
 
     SharedBuffer* data() { return m_data.get(); }
 
-    // It may look unusual that there is no start animation call as public API.  This is because
-    // we start and stop animating lazily.  Animation begins whenever someone draws the image.  It will
-    // automatically pause once all observers no longer want to render the image anywhere.
+    // Animation begins whenever someone draws the image, so startAnimation() is not normally called.
+    // It will automatically pause once all observers no longer want to render the image anywhere.
+    virtual void startAnimation(bool /*catchUpIfNecessary*/ = true) { }
     virtual void stopAnimation() {}
     virtual void resetAnimation() {}
     
@@ -137,7 +137,7 @@ public:
 protected:
     static void fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op);
 
-private:
+//private:
 #if PLATFORM(WIN)
     virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator) { }
 #endif
@@ -149,8 +149,6 @@ private:
     virtual bool mayFillWithSolidColor() const { return false; }
     virtual Color solidColor() const { return Color(); }
     
-    virtual void startAnimation() { }
-    
     virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
                              const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
 #if PLATFORM(CG)
Index: src/3rdParty/webkit/work/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
===================================================================
--- src.orig/3rdParty/webkit/work/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
+++ src/3rdParty/webkit/work/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
@@ -150,11 +150,25 @@ int GIFImageDecoder::frameCount()
 // The number of repetitions to perform for an animation loop.
 int GIFImageDecoder::repetitionCount() const
 {
-    // We don't have to do any decoding to determine this, since the loop count was determined after
-    // the initial query for size.
-    if (m_reader)
-        return m_reader->repetitionCount();
-    return cAnimationNone;
+    // This value can arrive at any point in the image data stream.  Most GIFs
+    // in the wild declare it near the beginning of the file, so it usually is
+    // set by the time we've decoded the size, but (depending on the GIF and the
+    // packets sent back by the webserver) not always.  Our caller is
+    // responsible for waiting until image decoding has finished to ask this if
+    // it needs an authoritative answer.  In the meantime, we should default to
+    // "loop once".
+    if (m_reader) {
+        // Added wrinkle: ImageSource::clear() may destroy the reader, making
+        // the result from the reader _less_ authoritative on future calls.  To
+        // detect this, the reader returns cLoopCountNotSeen (-2) instead of
+        // cAnimationLoopOnce (-1) when its current incarnation hasn't actually
+        // seen a loop count yet; in this case we return our previously-cached
+        // value.
+        const int repetitionCount = m_reader->repetitionCount();
+        if (repetitionCount != cLoopCountNotSeen)
+            m_repetitionCount = repetitionCount;
+    }
+    return m_repetitionCount;
 }
 
 RGBA32Buffer* GIFImageDecoder::frameBufferAtIndex(size_t index)
@@ -400,6 +414,8 @@ void GIFImageDecoder::frameComplete(unsi
 
 void GIFImageDecoder::gifComplete()
 {
+    if (m_reader)
+        m_repetitionCount = m_reader->repetitionCount();
     delete m_reader;
     m_reader = 0;
 }
Index: src/3rdParty/webkit/work/WebCore/platform/image-decoders/gif/GIFImageReader.h
===================================================================
--- src.orig/3rdParty/webkit/work/WebCore/platform/image-decoders/gif/GIFImageReader.h
+++ src/3rdParty/webkit/work/WebCore/platform/image-decoders/gif/GIFImageReader.h
@@ -47,6 +47,8 @@
 #define MAX_COLORS           256
 #define MAX_HOLD_SIZE        256
 
+const int cLoopCountNotSeen = -2;
+
 /* gif2.h  
    The interface for the GIF87/89a decoder. 
 */
@@ -187,7 +189,7 @@ struct GIFImageReader {
         screen_bgcolor = version = 0;
         screen_width = screen_height = 0;
         global_colormap_size = images_decoded = images_count = 0;
-        loop_count = -1;
+        loop_count = cLoopCountNotSeen;
         count = 0;
     }
 
Index: src/3rdParty/webkit/work/WebCore/platform/image-decoders/gif/GIFImageDecoder.h
===================================================================
--- src.orig/3rdParty/webkit/work/WebCore/platform/image-decoders/gif/GIFImageDecoder.h
+++ src/3rdParty/webkit/work/WebCore/platform/image-decoders/gif/GIFImageDecoder.h
@@ -79,6 +79,7 @@ private:
 
     bool m_frameCountValid;
     bool m_currentBufferSawAlpha;
+    mutable int m_repetitionCount;
     mutable GIFImageDecoderPrivate* m_reader;
 };
 
