2007-07-05 Alp Toker <alp.toker@collabora.co.uk>
[WebKit-https.git] / WebCore / platform / graphics / cairo / ImageSourceCairo.cpp
1 /*
2  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
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 "ImageSource.h"
29 #include "SharedBuffer.h"
30
31 #if PLATFORM(CAIRO)
32
33 #include "GIFImageDecoder.h"
34 #include "JPEGImageDecoder.h"
35 #include "PNGImageDecoder.h"
36 #include "BMPImageDecoder.h"
37 #include "ICOImageDecoder.h"
38 #include "XBMImageDecoder.h"
39
40 #include <cairo.h>
41
42 namespace WebCore {
43
44 ImageDecoder* createDecoder(const Vector<char>& data)
45 {
46     // We need at least 4 bytes to figure out what kind of image we're dealing with.
47     int length = data.size();
48     if (length < 4)
49         return 0;
50
51     const unsigned char* uContents = (const unsigned char*)data.data();
52     const char* contents = data.data();
53
54     // GIFs begin with GIF8(7 or 9).
55     if (strncmp(contents, "GIF8", 4) == 0)
56         return new GIFImageDecoder();
57
58     // Test for PNG.
59     if (uContents[0]==0x89 &&
60         uContents[1]==0x50 &&
61         uContents[2]==0x4E &&
62         uContents[3]==0x47)
63         return new PNGImageDecoder();
64
65     // JPEG
66     if (uContents[0]==0xFF &&
67         uContents[1]==0xD8 &&
68         uContents[2]==0xFF)
69         return new JPEGImageDecoder();
70
71     // BMP
72     if (strncmp(contents, "BM", 2) == 0)
73         return new BMPImageDecoder();
74
75     // ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
76     // CURs begin with 2-byte 0 followed by 2-byte 2.
77     if (!memcmp(contents, "\000\000\001\000", 4) ||
78         !memcmp(contents, "\000\000\002\000", 4))
79         return new ICOImageDecoder();
80    
81     // XBMs require 8 bytes of info.
82     if (length >= 8 && strncmp(contents, "#define ", 8) == 0)
83         return new XBMImageDecoder();
84
85     // Give up. We don't know what the heck this is.
86     return 0;
87 }
88
89 ImageSource::ImageSource()
90   : m_decoder(0)
91 {}
92
93 ImageSource::~ImageSource()
94 {
95     clear();
96 }
97
98 void ImageSource::clear()
99 {
100     delete m_decoder;
101     m_decoder = 0;
102 }
103
104 bool ImageSource::initialized() const
105 {
106     return m_decoder;
107 }
108
109 void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
110 {
111     // Make the decoder by sniffing the bytes.
112     // This method will examine the data and instantiate an instance of the appropriate decoder plugin.
113     // If insufficient bytes are available to determine the image type, no decoder plugin will be
114     // made.
115     delete m_decoder;
116     m_decoder = createDecoder(data->buffer());
117     if (!m_decoder)
118         return;
119     m_decoder->setData(data->buffer(), allDataReceived);
120 }
121
122 bool ImageSource::isSizeAvailable()
123 {
124     if (!m_decoder)
125         return false;
126
127     return m_decoder->isSizeAvailable();
128 }
129
130 IntSize ImageSource::size() const
131 {
132     if (!m_decoder)
133         return IntSize();
134
135     return m_decoder->size();
136 }
137
138 int ImageSource::repetitionCount()
139 {
140     if (!m_decoder)
141         return cAnimationNone;
142
143     return m_decoder->repetitionCount();
144 }
145
146 size_t ImageSource::frameCount() const
147 {
148     return m_decoder ? m_decoder->frameCount() : 0;
149 }
150
151 NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
152 {
153     if (!m_decoder)
154         return 0;
155
156     RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
157     if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
158         return 0;
159
160     return cairo_image_surface_create_for_data((unsigned char*)buffer->bytes().data(),
161                                                CAIRO_FORMAT_ARGB32,
162                                                size().width(),
163                                                buffer->height(),
164                                                size().width()*4);
165 }
166
167 bool ImageSource::frameIsCompleteAtIndex(size_t index)
168 {
169     if (!m_decoder)
170         return false;
171
172     RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
173     return buffer && buffer->status() == RGBA32Buffer::FrameComplete;
174 }
175
176 float ImageSource::frameDurationAtIndex(size_t index)
177 {
178     if (!m_decoder)
179         return 0;
180
181     RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
182     if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
183         return 0;
184
185     return buffer->duration() / 1000.0f;
186 }
187
188 bool ImageSource::frameHasAlphaAtIndex(size_t index)
189 {
190     if (!m_decoder || !m_decoder->supportsAlpha())
191         return false;
192
193     RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
194     if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
195         return false;
196
197     return buffer->hasAlpha();
198 }
199
200 }
201
202 #endif // PLATFORM(CAIRO)