Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2006 Samuel Weinig (sam.weinig (at) gmail.com)
      3  * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "platform/graphics/BitmapImage.h"
     29 
     30 #include "platform/Timer.h"
     31 #include "platform/TraceEvent.h"
     32 #include "platform/geometry/FloatRect.h"
     33 #include "platform/graphics/GraphicsContextStateSaver.h"
     34 #include "platform/graphics/ImageObserver.h"
     35 #include "platform/graphics/skia/NativeImageSkia.h"
     36 #include "platform/graphics/skia/SkiaUtils.h"
     37 #include "wtf/PassRefPtr.h"
     38 #include "wtf/text/WTFString.h"
     39 
     40 namespace blink {
     41 
     42 PassRefPtr<BitmapImage> BitmapImage::create(PassRefPtr<NativeImageSkia> nativeImage, ImageObserver* observer)
     43 {
     44     if (!nativeImage) {
     45         return BitmapImage::create(observer);
     46     }
     47 
     48     return adoptRef(new BitmapImage(nativeImage, observer));
     49 }
     50 
     51 BitmapImage::BitmapImage(ImageObserver* observer)
     52     : Image(observer)
     53     , m_currentFrame(0)
     54     , m_frames()
     55     , m_frameTimer(0)
     56     , m_repetitionCount(cAnimationNone)
     57     , m_repetitionCountStatus(Unknown)
     58     , m_repetitionsComplete(0)
     59     , m_desiredFrameStartTime(0)
     60     , m_frameCount(0)
     61     , m_isSolidColor(false)
     62     , m_checkedForSolidColor(false)
     63     , m_animationFinished(false)
     64     , m_allDataReceived(false)
     65     , m_haveSize(false)
     66     , m_sizeAvailable(false)
     67     , m_hasUniformFrameSize(true)
     68     , m_haveFrameCount(false)
     69 {
     70 }
     71 
     72 BitmapImage::BitmapImage(PassRefPtr<NativeImageSkia> nativeImage, ImageObserver* observer)
     73     : Image(observer)
     74     , m_size(nativeImage->bitmap().width(), nativeImage->bitmap().height())
     75     , m_currentFrame(0)
     76     , m_frames(0)
     77     , m_frameTimer(0)
     78     , m_repetitionCount(cAnimationNone)
     79     , m_repetitionCountStatus(Unknown)
     80     , m_repetitionsComplete(0)
     81     , m_frameCount(1)
     82     , m_isSolidColor(false)
     83     , m_checkedForSolidColor(false)
     84     , m_animationFinished(true)
     85     , m_allDataReceived(true)
     86     , m_haveSize(true)
     87     , m_sizeAvailable(true)
     88     , m_haveFrameCount(true)
     89 {
     90     // Since we don't have a decoder, we can't figure out the image orientation.
     91     // Set m_sizeRespectingOrientation to be the same as m_size so it's not 0x0.
     92     m_sizeRespectingOrientation = m_size;
     93 
     94     m_frames.grow(1);
     95     m_frames[0].m_hasAlpha = !nativeImage->bitmap().isOpaque();
     96     m_frames[0].m_frame = nativeImage;
     97     m_frames[0].m_haveMetadata = true;
     98 
     99     checkForSolidColor();
    100 }
    101 
    102 BitmapImage::~BitmapImage()
    103 {
    104     stopAnimation();
    105 }
    106 
    107 bool BitmapImage::isBitmapImage() const
    108 {
    109     return true;
    110 }
    111 
    112 bool BitmapImage::currentFrameHasSingleSecurityOrigin() const
    113 {
    114     return true;
    115 }
    116 
    117 void BitmapImage::destroyDecodedData(bool destroyAll)
    118 {
    119     for (size_t i = 0; i < m_frames.size(); ++i) {
    120         // The underlying frame isn't actually changing (we're just trying to
    121         // save the memory for the framebuffer data), so we don't need to clear
    122         // the metadata.
    123         m_frames[i].clear(false);
    124     }
    125 
    126     destroyMetadataAndNotify(m_source.clearCacheExceptFrame(destroyAll ? kNotFound : m_currentFrame));
    127 }
    128 
    129 void BitmapImage::destroyDecodedDataIfNecessary()
    130 {
    131     // Animated images >5MB are considered large enough that we'll only hang on
    132     // to one frame at a time.
    133     static const size_t cLargeAnimationCutoff = 5242880;
    134     size_t allFrameBytes = 0;
    135     for (size_t i = 0; i < m_frames.size(); ++i)
    136         allFrameBytes += m_frames[i].m_frameBytes;
    137 
    138     if (allFrameBytes > cLargeAnimationCutoff)
    139         destroyDecodedData(false);
    140 }
    141 
    142 void BitmapImage::destroyMetadataAndNotify(size_t frameBytesCleared)
    143 {
    144     m_isSolidColor = false;
    145     m_checkedForSolidColor = false;
    146 
    147     if (frameBytesCleared && imageObserver())
    148         imageObserver()->decodedSizeChanged(this, -safeCast<int>(frameBytesCleared));
    149 }
    150 
    151 void BitmapImage::cacheFrame(size_t index)
    152 {
    153     size_t numFrames = frameCount();
    154     if (m_frames.size() < numFrames)
    155         m_frames.grow(numFrames);
    156 
    157     m_frames[index].m_frame = m_source.createFrameAtIndex(index);
    158     if (numFrames == 1 && m_frames[index].m_frame)
    159         checkForSolidColor();
    160 
    161     m_frames[index].m_orientation = m_source.orientationAtIndex(index);
    162     m_frames[index].m_haveMetadata = true;
    163     m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index);
    164     if (repetitionCount(false) != cAnimationNone)
    165         m_frames[index].m_duration = m_source.frameDurationAtIndex(index);
    166     m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index);
    167     m_frames[index].m_frameBytes = m_source.frameBytesAtIndex(index);
    168 
    169     const IntSize frameSize(index ? m_source.frameSizeAtIndex(index) : m_size);
    170     if (frameSize != m_size)
    171         m_hasUniformFrameSize = false;
    172 
    173     if (m_frames[index].m_frame) {
    174         int deltaBytes = safeCast<int>(m_frames[index].m_frameBytes);
    175         // The fully-decoded frame will subsume the partially decoded data used
    176         // to determine image properties.
    177         if (imageObserver())
    178             imageObserver()->decodedSizeChanged(this, deltaBytes);
    179     }
    180 }
    181 
    182 void BitmapImage::updateSize() const
    183 {
    184     if (!m_sizeAvailable || m_haveSize)
    185         return;
    186 
    187     m_size = m_source.size();
    188     m_sizeRespectingOrientation = m_source.size(RespectImageOrientation);
    189     m_haveSize = true;
    190 }
    191 
    192 IntSize BitmapImage::size() const
    193 {
    194     updateSize();
    195     return m_size;
    196 }
    197 
    198 IntSize BitmapImage::sizeRespectingOrientation() const
    199 {
    200     updateSize();
    201     return m_sizeRespectingOrientation;
    202 }
    203 
    204 bool BitmapImage::getHotSpot(IntPoint& hotSpot) const
    205 {
    206     return m_source.getHotSpot(hotSpot);
    207 }
    208 
    209 bool BitmapImage::dataChanged(bool allDataReceived)
    210 {
    211     TRACE_EVENT0("blink", "BitmapImage::dataChanged");
    212 
    213     // Clear all partially-decoded frames. For most image formats, there is only
    214     // one frame, but at least GIF and ICO can have more. With GIFs, the frames
    215     // come in order and we ask to decode them in order, waiting to request a
    216     // subsequent frame until the prior one is complete. Given that we clear
    217     // incomplete frames here, this means there is at most one incomplete frame
    218     // (even if we use destroyDecodedData() -- since it doesn't reset the
    219     // metadata), and it is after all the complete frames.
    220     //
    221     // With ICOs, on the other hand, we may ask for arbitrary frames at
    222     // different times (e.g. because we're displaying a higher-resolution image
    223     // in the content area and using a lower-resolution one for the favicon),
    224     // and the frames aren't even guaranteed to appear in the file in the same
    225     // order as in the directory, so an arbitrary number of the frames might be
    226     // incomplete (if we ask for frames for which we've not yet reached the
    227     // start of the frame data), and any or none of them might be the particular
    228     // frame affected by appending new data here. Thus we have to clear all the
    229     // incomplete frames to be safe.
    230     unsigned frameBytesCleared = 0;
    231     for (size_t i = 0; i < m_frames.size(); ++i) {
    232         // NOTE: Don't call frameIsCompleteAtIndex() here, that will try to
    233         // decode any uncached (i.e. never-decoded or
    234         // cleared-on-a-previous-pass) frames!
    235         unsigned frameBytes = m_frames[i].m_frameBytes;
    236         if (m_frames[i].m_haveMetadata && !m_frames[i].m_isComplete)
    237             frameBytesCleared += (m_frames[i].clear(true) ? frameBytes : 0);
    238     }
    239     destroyMetadataAndNotify(frameBytesCleared);
    240 
    241     // Feed all the data we've seen so far to the image decoder.
    242     m_allDataReceived = allDataReceived;
    243     ASSERT(data());
    244     m_source.setData(*data(), allDataReceived);
    245 
    246     m_haveFrameCount = false;
    247     m_hasUniformFrameSize = true;
    248     return isSizeAvailable();
    249 }
    250 
    251 bool BitmapImage::hasColorProfile() const
    252 {
    253     return m_source.hasColorProfile();
    254 }
    255 
    256 String BitmapImage::filenameExtension() const
    257 {
    258     return m_source.filenameExtension();
    259 }
    260 
    261 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, WebBlendMode blendMode)
    262 {
    263     draw(ctxt, dstRect, srcRect, compositeOp, blendMode, DoNotRespectImageOrientation);
    264 }
    265 
    266 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, WebBlendMode blendMode, RespectImageOrientationEnum shouldRespectImageOrientation)
    267 {
    268     // Spin the animation to the correct frame before we try to draw it, so we
    269     // don't draw an old frame and then immediately need to draw a newer one,
    270     // causing flicker and wasting CPU.
    271     startAnimation();
    272 
    273     RefPtr<NativeImageSkia> image = nativeImageForCurrentFrame();
    274     if (!image)
    275         return; // It's too early and we don't have an image yet.
    276 
    277     FloatRect normDstRect = adjustForNegativeSize(dstRect);
    278     FloatRect normSrcRect = adjustForNegativeSize(srcRect);
    279     normSrcRect.intersect(FloatRect(0, 0, image->bitmap().width(), image->bitmap().height()));
    280 
    281     if (normSrcRect.isEmpty() || normDstRect.isEmpty())
    282         return; // Nothing to draw.
    283 
    284     ImageOrientation orientation = DefaultImageOrientation;
    285     if (shouldRespectImageOrientation == RespectImageOrientation)
    286         orientation = frameOrientationAtIndex(m_currentFrame);
    287 
    288     GraphicsContextStateSaver saveContext(*ctxt, false);
    289     if (orientation != DefaultImageOrientation) {
    290         saveContext.save();
    291 
    292         // ImageOrientation expects the origin to be at (0, 0)
    293         ctxt->translate(normDstRect.x(), normDstRect.y());
    294         normDstRect.setLocation(FloatPoint());
    295 
    296         ctxt->concatCTM(orientation.transformFromDefault(normDstRect.size()));
    297 
    298         if (orientation.usesWidthAsHeight()) {
    299             // The destination rect will have it's width and height already reversed for the orientation of
    300             // the image, as it was needed for page layout, so we need to reverse it back here.
    301             normDstRect = FloatRect(normDstRect.x(), normDstRect.y(), normDstRect.height(), normDstRect.width());
    302         }
    303     }
    304 
    305     image->draw(ctxt, normSrcRect, normDstRect, compositeOp, blendMode);
    306 
    307     if (ImageObserver* observer = imageObserver())
    308         observer->didDraw(this);
    309 }
    310 
    311 void BitmapImage::resetDecoder()
    312 {
    313     ASSERT(isMainThread());
    314 
    315     m_source.resetDecoder();
    316 }
    317 
    318 size_t BitmapImage::frameCount()
    319 {
    320     if (!m_haveFrameCount) {
    321         m_frameCount = m_source.frameCount();
    322         // If decoder is not initialized yet, m_source.frameCount() returns 0.
    323         if (m_frameCount)
    324             m_haveFrameCount = true;
    325     }
    326 
    327     return m_frameCount;
    328 }
    329 
    330 bool BitmapImage::isSizeAvailable()
    331 {
    332     if (m_sizeAvailable)
    333         return true;
    334 
    335     m_sizeAvailable = m_source.isSizeAvailable();
    336 
    337     return m_sizeAvailable;
    338 }
    339 
    340 bool BitmapImage::ensureFrameIsCached(size_t index)
    341 {
    342     if (index >= frameCount())
    343         return false;
    344 
    345     if (index >= m_frames.size() || !m_frames[index].m_frame)
    346         cacheFrame(index);
    347 
    348     return true;
    349 }
    350 
    351 PassRefPtr<NativeImageSkia> BitmapImage::frameAtIndex(size_t index)
    352 {
    353     if (!ensureFrameIsCached(index))
    354         return nullptr;
    355 
    356     return m_frames[index].m_frame;
    357 }
    358 
    359 bool BitmapImage::frameIsCompleteAtIndex(size_t index)
    360 {
    361     if (index < m_frames.size() && m_frames[index].m_haveMetadata && m_frames[index].m_isComplete)
    362         return true;
    363 
    364     return m_source.frameIsCompleteAtIndex(index);
    365 }
    366 
    367 float BitmapImage::frameDurationAtIndex(size_t index)
    368 {
    369     if (index < m_frames.size() && m_frames[index].m_haveMetadata)
    370         return m_frames[index].m_duration;
    371 
    372     return m_source.frameDurationAtIndex(index);
    373 }
    374 
    375 PassRefPtr<NativeImageSkia> BitmapImage::nativeImageForCurrentFrame()
    376 {
    377     return frameAtIndex(currentFrame());
    378 }
    379 
    380 PassRefPtr<Image> BitmapImage::imageForDefaultFrame()
    381 {
    382     if (frameCount() > 1 && frameAtIndex(0))
    383         return BitmapImage::create(frameAtIndex(0));
    384 
    385     return Image::imageForDefaultFrame();
    386 }
    387 
    388 bool BitmapImage::frameHasAlphaAtIndex(size_t index)
    389 {
    390     if (m_frames.size() <= index)
    391         return true;
    392 
    393     if (m_frames[index].m_haveMetadata)
    394         return m_frames[index].m_hasAlpha;
    395 
    396     return m_source.frameHasAlphaAtIndex(index);
    397 }
    398 
    399 bool BitmapImage::currentFrameKnownToBeOpaque()
    400 {
    401     return !frameHasAlphaAtIndex(currentFrame());
    402 }
    403 
    404 ImageOrientation BitmapImage::currentFrameOrientation()
    405 {
    406     return frameOrientationAtIndex(currentFrame());
    407 }
    408 
    409 ImageOrientation BitmapImage::frameOrientationAtIndex(size_t index)
    410 {
    411     if (m_frames.size() <= index)
    412         return DefaultImageOrientation;
    413 
    414     if (m_frames[index].m_haveMetadata)
    415         return m_frames[index].m_orientation;
    416 
    417     return m_source.orientationAtIndex(index);
    418 }
    419 
    420 #if ENABLE(ASSERT)
    421 bool BitmapImage::notSolidColor()
    422 {
    423     return size().width() != 1 || size().height() != 1 || frameCount() > 1;
    424 }
    425 #endif
    426 
    427 int BitmapImage::repetitionCount(bool imageKnownToBeComplete)
    428 {
    429     if ((m_repetitionCountStatus == Unknown) || ((m_repetitionCountStatus == Uncertain) && imageKnownToBeComplete)) {
    430         // Snag the repetition count.  If |imageKnownToBeComplete| is false, the
    431         // repetition count may not be accurate yet for GIFs; in this case the
    432         // decoder will default to cAnimationLoopOnce, and we'll try and read
    433         // the count again once the whole image is decoded.
    434         m_repetitionCount = m_source.repetitionCount();
    435         m_repetitionCountStatus = (imageKnownToBeComplete || m_repetitionCount == cAnimationNone) ? Certain : Uncertain;
    436     }
    437     return m_repetitionCount;
    438 }
    439 
    440 bool BitmapImage::shouldAnimate()
    441 {
    442     return (repetitionCount(false) != cAnimationNone && !m_animationFinished && imageObserver());
    443 }
    444 
    445 void BitmapImage::startAnimation(CatchUpAnimation catchUpIfNecessary)
    446 {
    447     if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
    448         return;
    449 
    450     // If we aren't already animating, set now as the animation start time.
    451     const double time = monotonicallyIncreasingTime();
    452     if (!m_desiredFrameStartTime)
    453         m_desiredFrameStartTime = time;
    454 
    455     // Don't advance the animation to an incomplete frame.
    456     size_t nextFrame = (m_currentFrame + 1) % frameCount();
    457     if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame))
    458         return;
    459 
    460     // Don't advance past the last frame if we haven't decoded the whole image
    461     // yet and our repetition count is potentially unset.  The repetition count
    462     // in a GIF can potentially come after all the rest of the image data, so
    463     // wait on it.
    464     if (!m_allDataReceived && repetitionCount(false) == cAnimationLoopOnce && m_currentFrame >= (frameCount() - 1))
    465         return;
    466 
    467     // Determine time for next frame to start.  By ignoring paint and timer lag
    468     // in this calculation, we make the animation appear to run at its desired
    469     // rate regardless of how fast it's being repainted.
    470     const double currentDuration = frameDurationAtIndex(m_currentFrame);
    471     m_desiredFrameStartTime += currentDuration;
    472 
    473     // When an animated image is more than five minutes out of date, the
    474     // user probably doesn't care about resyncing and we could burn a lot of
    475     // time looping through frames below.  Just reset the timings.
    476     const double cAnimationResyncCutoff = 5 * 60;
    477     if ((time - m_desiredFrameStartTime) > cAnimationResyncCutoff)
    478         m_desiredFrameStartTime = time + currentDuration;
    479 
    480     // The image may load more slowly than it's supposed to animate, so that by
    481     // the time we reach the end of the first repetition, we're well behind.
    482     // Clamp the desired frame start time in this case, so that we don't skip
    483     // frames (or whole iterations) trying to "catch up".  This is a tradeoff:
    484     // It guarantees users see the whole animation the second time through and
    485     // don't miss any repetitions, and is closer to what other browsers do; on
    486     // the other hand, it makes animations "less accurate" for pages that try to
    487     // sync an image and some other resource (e.g. audio), especially if users
    488     // switch tabs (and thus stop drawing the animation, which will pause it)
    489     // during that initial loop, then switch back later.
    490     if (nextFrame == 0 && m_repetitionsComplete == 0 && m_desiredFrameStartTime < time)
    491         m_desiredFrameStartTime = time;
    492 
    493     if (catchUpIfNecessary == DoNotCatchUp || time < m_desiredFrameStartTime) {
    494         // Haven't yet reached time for next frame to start; delay until then.
    495         m_frameTimer = new Timer<BitmapImage>(this, &BitmapImage::advanceAnimation);
    496         m_frameTimer->startOneShot(std::max(m_desiredFrameStartTime - time, 0.), FROM_HERE);
    497     } else {
    498         // We've already reached or passed the time for the next frame to start.
    499         // See if we've also passed the time for frames after that to start, in
    500         // case we need to skip some frames entirely.  Remember not to advance
    501         // to an incomplete frame.
    502         for (size_t frameAfterNext = (nextFrame + 1) % frameCount(); frameIsCompleteAtIndex(frameAfterNext); frameAfterNext = (nextFrame + 1) % frameCount()) {
    503             // Should we skip the next frame?
    504             double frameAfterNextStartTime = m_desiredFrameStartTime + frameDurationAtIndex(nextFrame);
    505             if (time < frameAfterNextStartTime)
    506                 break;
    507 
    508             // Yes; skip over it without notifying our observers.
    509             if (!internalAdvanceAnimation(true))
    510                 return;
    511             m_desiredFrameStartTime = frameAfterNextStartTime;
    512             nextFrame = frameAfterNext;
    513         }
    514 
    515         // Draw the next frame immediately.  Note that m_desiredFrameStartTime
    516         // may be in the past, meaning the next time through this function we'll
    517         // kick off the next advancement sooner than this frame's duration would
    518         // suggest.
    519         if (internalAdvanceAnimation(false)) {
    520             // The image region has been marked dirty, but once we return to our
    521             // caller, draw() will clear it, and nothing will cause the
    522             // animation to advance again.  We need to start the timer for the
    523             // next frame running, or the animation can hang.  (Compare this
    524             // with when advanceAnimation() is called, and the region is dirtied
    525             // while draw() is not in the callstack, meaning draw() gets called
    526             // to update the region and thus startAnimation() is reached again.)
    527             // NOTE: For large images with slow or heavily-loaded systems,
    528             // throwing away data as we go (see destroyDecodedData()) means we
    529             // can spend so much time re-decoding data above that by the time we
    530             // reach here we're behind again.  If we let startAnimation() run
    531             // the catch-up code again, we can get long delays without painting
    532             // as we race the timer, or even infinite recursion.  In this
    533             // situation the best we can do is to simply change frames as fast
    534             // as possible, so force startAnimation() to set a zero-delay timer
    535             // and bail out if we're not caught up.
    536             startAnimation(DoNotCatchUp);
    537         }
    538     }
    539 }
    540 
    541 void BitmapImage::stopAnimation()
    542 {
    543     // This timer is used to animate all occurrences of this image.  Don't invalidate
    544     // the timer unless all renderers have stopped drawing.
    545     delete m_frameTimer;
    546     m_frameTimer = 0;
    547 }
    548 
    549 void BitmapImage::resetAnimation()
    550 {
    551     stopAnimation();
    552     m_currentFrame = 0;
    553     m_repetitionsComplete = 0;
    554     m_desiredFrameStartTime = 0;
    555     m_animationFinished = false;
    556 
    557     // For extremely large animations, when the animation is reset, we just throw everything away.
    558     destroyDecodedDataIfNecessary();
    559 }
    560 
    561 bool BitmapImage::maybeAnimated()
    562 {
    563     if (m_animationFinished)
    564         return false;
    565     if (frameCount() > 1)
    566         return true;
    567 
    568     return m_source.repetitionCount() != cAnimationNone;
    569 }
    570 
    571 void BitmapImage::advanceAnimation(Timer<BitmapImage>*)
    572 {
    573     internalAdvanceAnimation(false);
    574     // At this point the image region has been marked dirty, and if it's
    575     // onscreen, we'll soon make a call to draw(), which will call
    576     // startAnimation() again to keep the animation moving.
    577 }
    578 
    579 bool BitmapImage::internalAdvanceAnimation(bool skippingFrames)
    580 {
    581     // Stop the animation.
    582     stopAnimation();
    583 
    584     // See if anyone is still paying attention to this animation.  If not, we don't
    585     // advance and will remain suspended at the current frame until the animation is resumed.
    586     if (!skippingFrames && imageObserver()->shouldPauseAnimation(this))
    587         return false;
    588 
    589     ++m_currentFrame;
    590     bool advancedAnimation = true;
    591     if (m_currentFrame >= frameCount()) {
    592         ++m_repetitionsComplete;
    593 
    594         // Get the repetition count again.  If we weren't able to get a
    595         // repetition count before, we should have decoded the whole image by
    596         // now, so it should now be available.
    597         // Note that we don't need to special-case cAnimationLoopOnce here
    598         // because it is 0 (see comments on its declaration in ImageSource.h).
    599         if (repetitionCount(true) != cAnimationLoopInfinite && m_repetitionsComplete > m_repetitionCount) {
    600             m_animationFinished = true;
    601             m_desiredFrameStartTime = 0;
    602             --m_currentFrame;
    603             advancedAnimation = false;
    604         } else
    605             m_currentFrame = 0;
    606     }
    607     destroyDecodedDataIfNecessary();
    608 
    609     // We need to draw this frame if we advanced to it while not skipping, or if
    610     // while trying to skip frames we hit the last frame and thus had to stop.
    611     if (skippingFrames != advancedAnimation)
    612         imageObserver()->animationAdvanced(this);
    613     return advancedAnimation;
    614 }
    615 
    616 void BitmapImage::checkForSolidColor()
    617 {
    618     m_isSolidColor = false;
    619     m_checkedForSolidColor = true;
    620 
    621     if (frameCount() > 1)
    622         return;
    623 
    624     RefPtr<NativeImageSkia> frame = frameAtIndex(0);
    625 
    626     if (frame && size().width() == 1 && size().height() == 1) {
    627         SkAutoLockPixels lock(frame->bitmap());
    628         if (!frame->bitmap().getPixels())
    629             return;
    630 
    631         m_isSolidColor = true;
    632         m_solidColor = Color(frame->bitmap().getColor(0, 0));
    633     }
    634 }
    635 
    636 bool BitmapImage::mayFillWithSolidColor()
    637 {
    638     if (!m_checkedForSolidColor && frameCount() > 0) {
    639         checkForSolidColor();
    640         ASSERT(m_checkedForSolidColor);
    641     }
    642 
    643     return m_isSolidColor && !m_currentFrame;
    644 }
    645 
    646 Color BitmapImage::solidColor() const
    647 {
    648     return m_solidColor;
    649 }
    650 
    651 } // namespace blink
    652