2 * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
3 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
30 #include "FloatRect.h"
32 #include "ImageAnimationObserver.h"
34 #include "PlatformString.h"
36 #include <wtf/Vector.h>
39 // FIXME: Will go away when we make PDF a subclass.
40 #include "PDFDocumentImage.h"
45 // ================================================
47 // ================================================
50 : m_currentFrame(0), m_frames(0), m_animationObserver(0),
51 m_frameTimer(0), m_repetitionCount(0), m_repetitionsComplete(0),
52 m_isSolidColor(false), m_animatingImageType(true), m_animationFinished(false),
53 m_haveSize(false), m_sizeAvailable(false)
56 m_isPDF = false; // FIXME: Will go away when we make PDF a subclass.
62 Image::Image(ImageAnimationObserver* observer, bool isPDF)
63 : m_currentFrame(0), m_frames(0), m_animationObserver(0),
64 m_frameTimer(0), m_repetitionCount(0), m_repetitionsComplete(0),
65 m_isSolidColor(false), m_animatingImageType(true), m_animationFinished(false),
66 m_haveSize(false), m_sizeAvailable(false)
70 m_isPDF = isPDF; // FIXME: Will go away when we make PDF a subclass.
73 m_animationObserver = observer;
81 delete m_PDFDoc; // FIXME: Will go away when we make a PDF image subclass.
85 void Image::invalidateData()
87 // Destroy the cached images and release them.
88 if (m_frames.size()) {
89 m_frames.last().clear();
90 m_isSolidColor = false;
91 invalidatePlatformData();
95 void Image::cacheFrame(size_t index)
97 size_t numFrames = frameCount();
98 if (!m_frames.size() && shouldAnimate()) {
99 // Snag the repetition count.
100 m_repetitionCount = m_source.repetitionCount();
101 if (m_repetitionCount == cAnimationNone)
102 m_animatingImageType = false;
105 if (m_frames.size() < numFrames)
106 m_frames.resize(numFrames);
108 m_frames[index].m_frame = m_source.createFrameAtIndex(index);
109 if (m_frames[index].m_frame)
110 checkForSolidColor();
113 m_frames[index].m_duration = m_source.frameDurationAtIndex(index);
114 m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index);
117 bool Image::isNull() const
119 return size().isEmpty();
122 IntSize Image::size() const
125 // FIXME: Will go away when we make PDF a subclass.
128 FloatSize size = m_PDFDoc->size();
129 return IntSize((int)size.width(), (int)size.height());
134 if (m_sizeAvailable && !m_haveSize) {
135 m_size = m_source.size();
141 bool Image::setData(bool allDataReceived)
143 int length = m_data.size();
147 #ifdef kImageBytesCutoff
148 // This is a hack to help with testing display of partially-loaded images.
149 // To enable it, define kImageBytesCutoff to be a size smaller than that of the image files
150 // being loaded. They'll never finish loading.
151 if (length > kImageBytesCutoff) {
152 length = kImageBytesCutoff;
153 allDataReceived = false;
158 // Avoid the extra copy of bytes by just handing the byte array directly to a CFDataRef.
159 CFDataRef data = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(m_data.data()), length, kCFAllocatorNull);
160 bool result = setNativeData(data, allDataReceived);
163 bool result = setNativeData(&m_data, allDataReceived);
169 bool Image::setNativeData(NativeBytePtr data, bool allDataReceived)
172 // FIXME: Will go away when we make PDF a subclass.
174 if (allDataReceived && !m_PDFDoc)
175 m_PDFDoc = new PDFDocumentImage(data);
182 // Feed all the data we've seen so far to the image decoder.
183 m_source.setData(data, allDataReceived);
185 // Image properties will not be available until the first frame of the file
186 // reaches kCGImageStatusIncomplete.
187 return isSizeAvailable();
190 size_t Image::frameCount()
192 return m_source.frameCount();
195 bool Image::isSizeAvailable()
200 m_sizeAvailable = m_source.isSizeAvailable();
202 return m_sizeAvailable;
206 NativeImagePtr Image::frameAtIndex(size_t index)
208 if (index >= frameCount())
211 if (index >= m_frames.size() || !m_frames[index].m_frame)
214 return m_frames[index].m_frame;
217 float Image::frameDurationAtIndex(size_t index)
219 if (index >= frameCount())
222 if (index >= m_frames.size() || !m_frames[index].m_frame)
225 return m_frames[index].m_duration;
228 bool Image::frameHasAlphaAtIndex(size_t index)
230 if (index >= frameCount())
233 if (index >= m_frames.size() || !m_frames[index].m_frame)
236 return m_frames[index].m_hasAlpha;
239 bool Image::shouldAnimate()
241 return (m_animatingImageType && !m_animationFinished && m_animationObserver);
244 void Image::startAnimation()
246 if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
249 m_frameTimer = new Timer<Image>(this, &Image::advanceAnimation);
250 m_frameTimer->startOneShot(frameDurationAtIndex(m_currentFrame));
253 void Image::stopAnimation()
255 // This timer is used to animate all occurrences of this image. Don't invalidate
256 // the timer unless all renderers have stopped drawing.
261 void Image::resetAnimation()
265 m_repetitionsComplete = 0;
266 m_animationFinished = false;
270 void Image::advanceAnimation(Timer<Image>* timer)
272 // Stop the animation.
275 // See if anyone is still paying attention to this animation. If not, we don't
276 // advance and will simply pause the animation.
277 if (animationObserver()->shouldStopAnimation(this))
281 if (m_currentFrame >= frameCount()) {
282 m_repetitionsComplete += 1;
283 if (m_repetitionCount && m_repetitionsComplete >= m_repetitionCount) {
284 m_animationFinished = false;
291 // Notify our observer that the animation has advanced.
292 animationObserver()->animationAdvanced(this);
294 // Kick off a timer to move to the next frame.
295 m_frameTimer = new Timer<Image>(this, &Image::advanceAnimation);
296 m_frameTimer->startOneShot(frameDurationAtIndex(m_currentFrame));
299 IntRect Image::rect() const
301 return IntRect(IntPoint(), size());
304 int Image::width() const
306 return size().width();
309 int Image::height() const
311 return size().height();