Beispiel #1
0
void CachedImage::clear()
{
    destroyDecodedData();
    clearImage();
    m_pendingContainerSizeRequests.clear();
    setEncodedSize(0);
}
Beispiel #2
0
Image::~Image()
{
    // Null out the image observer so that we don't incorrectly communicate that decoded data is being destroyed during destruction. 
 	m_imageObserver = 0;
    destroyDecodedData();
    stopAnimation();
    destroyNativeData();
}
Beispiel #3
0
TEST_F(BitmapImageTest, destroyDecodedData) {
    loadImage("/LayoutTests/fast/images/resources/animated-10color.gif");
    size_t totalSize = decodedSize();
    EXPECT_GT(totalSize, 0u);
    destroyDecodedData();
    EXPECT_EQ(-static_cast<int>(totalSize), lastDecodedSizeChange());
    EXPECT_EQ(0u, decodedSize());
}
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);
}
TEST_F(BitmapImageTest, destroyAllDecodedData)
{
    loadImage("/tests/fast/images/resources/animated-10color.gif");
    size_t totalSize = decodedSize();
    EXPECT_GT(totalSize, 0u);
    destroyDecodedData(true);
    EXPECT_EQ(-static_cast<int>(totalSize), m_imageObserver.m_lastDecodedSizeChangedDelta);
    EXPECT_EQ(0u, decodedSize());
}
TEST_F(BitmapImageTest, pngHasColorProfile)
{
    loadImage("/LayoutTests/fast/images/resources/palatted-color-png-gamma-one-color-profile.png");
    EXPECT_EQ(1u, decodedFramesCount());
    EXPECT_EQ(65536u, decodedSize());
    EXPECT_TRUE(m_image->hasColorProfile());

    destroyDecodedData(true);
}
TEST_F(BitmapImageTest, jpegHasColorProfile)
{
    loadImage("/LayoutTests/fast/images/resources/icc-v2-gbr.jpg");
    EXPECT_EQ(1u, decodedFramesCount());
    EXPECT_EQ(227700u, decodedSize());
    EXPECT_TRUE(m_image->hasColorProfile());

    destroyDecodedData(true);
}
TEST_F(BitmapImageTest, webpHasColorProfile)
{
    loadImage("/LayoutTests/fast/images/resources/webp-color-profile-lossy.webp");
    EXPECT_EQ(1u, decodedFramesCount());
    EXPECT_EQ(2560000u, decodedSize());
    EXPECT_TRUE(m_image->hasColorProfile());

    destroyDecodedData(true);
}
TEST_F(BitmapImageTest, destroyDecodedDataExceptCurrentFrame)
{
    loadImage("/tests/fast/images/resources/animated-10color.gif");
    size_t totalSize = decodedSize();
    size_t frame = frameCount() / 2;
    setCurrentFrame(frame);
    size_t size = frameDecodedSize(frame);
    destroyDecodedData(false);
    EXPECT_LT(m_imageObserver.m_lastDecodedSizeChangedDelta, 0);
    EXPECT_GE(m_imageObserver.m_lastDecodedSizeChangedDelta, -static_cast<int>(totalSize - size));
}
Beispiel #10
0
bool ImageFrameCache::destroyDecodedDataIfNecessary(bool destroyAll, size_t count)
{
    unsigned decodedSize = 0;
    for (auto& frame : m_frames)
        decodedSize += frame.frameBytes();
    
    if (decodedSize < LargeAnimationCutoff)
        return false;
    
    destroyDecodedData(destroyAll, count);
    return true;
}
Beispiel #11
0
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;
    unsigned allFrameBytes = 0;
    for (size_t i = 0; i < m_frames.size(); ++i)
        allFrameBytes += m_frames[i].m_frameBytes;

    if (allFrameBytes > cLargeAnimationCutoff)
        destroyDecodedData(destroyAll);
}
Beispiel #12
0
void BitmapImage::resetAnimation()
{
    stopAnimation();
    m_currentFrame = 0;
    m_repetitionsComplete = 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();
}
Beispiel #13
0
bool BitmapImage::dataChanged(bool allDataReceived)
{
    destroyDecodedData(true);
    
    // Feed all the data we've seen so far to the image decoder.
    m_allDataReceived = allDataReceived;
    m_source.setData(m_data.get(), allDataReceived);
    
    // Image properties will not be available until the first frame of the file
    // reaches kCGImageStatusIncomplete.
    return isSizeAvailable();
}
Beispiel #14
0
void BitmapImage::notifyObserverAndTrimDecodedData()
{
    // 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.  We save the
        // current frame since we'll need it in draw() anyway.
        destroyDecodedData(false, true);
    }
}
Beispiel #15
0
TEST_F(BitmapImageDeferredDecodingTest, correctDecodedDataSize)
{
    // When deferred decoding is enabled, requesting any one frame shouldn't
    // result in decoding any other frames.
    loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false);
    frameAtIndex(1);
    int frameSize = static_cast<int>(m_image->size().area() * sizeof(ImageFrame::PixelData));
    EXPECT_EQ(frameSize, m_imageObserver->m_lastDecodedSizeChangedDelta);
    frameAtIndex(0);

    // Trying to destroy all data except an undecoded frame should go ahead and
    // destroy all other frames.
    setCurrentFrame(2);
    destroyDecodedData(false);
    EXPECT_EQ(-frameSize * 2, m_imageObserver->m_lastDecodedSizeChangedDelta);
}
Beispiel #16
0
void BitmapImage::notifyObserverAndTrimDecodedData()
{
    // 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);
    }
}
Beispiel #17
0
TEST_F(BitmapImageTest, correctDecodedDataSize)
{
    // When requesting a frame of a multi-frame GIF causes another frame to be
    // decoded as well, both frames' sizes should be reported by the source and
    // thus included in the decoded size changed notification.
    loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false);
    frameAtIndex(1);
    int frameSize = static_cast<int>(m_image->size().area() * sizeof(ImageFrame::PixelData));
    EXPECT_EQ(frameSize * 2, m_imageObserver->m_lastDecodedSizeChangedDelta);

    // Trying to destroy all data except an undecoded frame should cause the
    // decoder to seek backwards and preserve the most recent previous frame
    // necessary to decode that undecoded frame, and destroy all other frames.
    setCurrentFrame(2);
    destroyDecodedData(false);
    EXPECT_EQ(-frameSize, m_imageObserver->m_lastDecodedSizeChangedDelta);
}
Beispiel #18
0
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 we have decoded frames but there is no encoded data, we shouldn't destroy
    // the decoded image since we won't be able to reconstruct it later.
    if (!data() && m_frames.size())
        return;

    unsigned allFrameBytes = 0;
    for (size_t i = 0; i < m_frames.size(); ++i)
        allFrameBytes += m_frames[i].m_frameBytes;

    if (allFrameBytes > cLargeAnimationCutoff)
        destroyDecodedData(destroyAll);
}
Beispiel #19
0
bool Image::setNativeData(NativeBytePtr data, bool allDataReceived)
{
#if __APPLE__
    // FIXME: Will go away when we make PDF a subclass.
    if (m_isPDF) {
        if (allDataReceived && !m_PDFDoc)
            m_PDFDoc = new PDFDocumentImage(data);
        return m_PDFDoc;
    }
#endif

    destroyDecodedData(true); 
    
    // Feed all the data we've seen so far to the image decoder.
    m_source.setData(data, allDataReceived);
    
    // Image properties will not be available until the first frame of the file
    // reaches kCGImageStatusIncomplete.
    return isSizeAvailable();
}
Beispiel #20
0
void Image::advanceAnimation(Timer<Image>* timer)
{
    // 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;
    
    m_currentFrame++;
    if (m_currentFrame >= frameCount()) {
        m_repetitionsComplete += 1;
        if (m_repetitionCount && m_repetitionsComplete >= m_repetitionCount) {
            m_animationFinished = true;
            m_currentFrame--;
            return;
        }
        m_currentFrame = 0;
    }
    
    // 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).
}
Beispiel #21
0
void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll)
{
    // Animated images over a certain size are considered large enough that we'll only hang on
    // to one frame at a time.
#if PLATFORM(IOS)
    const unsigned largeAnimationCutoff = 2097152;
#else
    const unsigned largeAnimationCutoff = 5242880;
#endif

    // If we have decoded frames but there is no encoded data, we shouldn't destroy
    // the decoded image since we won't be able to reconstruct it later.
    if (!data() && m_frames.size())
        return;

    unsigned allFrameBytes = 0;
    for (size_t i = 0; i < m_frames.size(); ++i)
        allFrameBytes += m_frames[i].usedFrameBytes();

    if (allFrameBytes > largeAnimationCutoff) {
        LOG(Images, "BitmapImage %p destroyDecodedDataIfNecessary destroyingData: allFrameBytes=%u cutoff=%u", this, allFrameBytes, largeAnimationCutoff);
        destroyDecodedData(destroyAll);
    }
}
Beispiel #22
0
void CachedImage::decodedDataDeletionTimerFired(Timer<CachedImage>*)
{
    ASSERT(!hasClients());
    destroyDecodedData();
}
Beispiel #23
0
void CachedImage::clear()
{
    destroyDecodedData();
    m_image = 0;
    setEncodedSize(0);
}
Beispiel #24
0
void CachedScript::decodedDataDeletionTimerFired(Timer<CachedScript>*)
{
    destroyDecodedData();
}
Beispiel #25
0
void CachedResource::decodedDataDeletionTimerFired()
{
    destroyDecodedData();
}