tizen beta release
[profile/ivi/webkit-efl.git] / Source / WebCore / platform / image-decoders / blackberry / JPEGImageDecoder.cpp
1 /*
2  * Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 // Implementation notes:
20 // Current implementation provides the source image size without doing a full
21 // decode. It seems that libimg does not support partial decoding.
22
23 #include "config.h"
24 #include "JPEGImageDecoder.h"
25
26 #include <errno.h>
27 #include <img/img.h>
28 #include <string.h>
29 #include <wtf/OwnArrayPtr.h>
30 #include <wtf/PassOwnPtr.h>
31
32 namespace WebCore {
33
34 static img_lib_t s_ilib;
35
36 static inline int libInit()
37 {
38     static bool s_initialized;
39     if (s_initialized)
40         return 0;
41
42     if (img_lib_attach(&s_ilib) != IMG_ERR_OK) {
43         LOG_ERROR("Unable to attach to libimg.");
44         return -1;
45     }
46     s_initialized = true;
47     return 0;
48 }
49
50 class ImageReader {
51 public:
52     ImageReader(const char* data, size_t dataSize)
53         : m_data(data)
54         , m_size(dataSize)
55         , m_width(0)
56         , m_height(0)
57     {
58         libInit();
59     }
60
61     void updateData(const char* data, size_t dataSize);
62     int setSize(size_t width, size_t height);
63     int sizeExtract(size_t& width, size_t& height);
64     int decode(size_t width, size_t height, ImageFrame*);
65
66 private:
67     const char* m_data;
68     size_t m_size;
69     size_t m_width;
70     size_t m_height;
71 };
72
73 // Function to get the original size of an image
74 static int imgDecodeSetup(_Uintptrt data, img_t* img, unsigned flags)
75 {
76     ImageReader* reader = reinterpret_cast<ImageReader*>(data);
77
78     if ((img->flags & (IMG_W | IMG_H)) == (IMG_W | IMG_H))
79         reader->setSize(img->w, img->h);
80
81     // Always: want to stop processing whether get a size or not.
82     return IMG_ERR_INTR;
83 }
84
85 void ImageReader::updateData(const char* data, size_t dataSize)
86 {
87     m_data = data;
88     m_size = dataSize;
89 }
90
91 int ImageReader::setSize(size_t width, size_t height)
92 {
93     m_width = width;
94     m_height = height;
95     return 0;
96 }
97
98 int ImageReader::sizeExtract(size_t& width, size_t& height)
99 {
100     img_decode_callouts_t callouts;
101     img_t img;
102     io_stream_t* iostream = io_open(IO_MEM, IO_READ, m_size, m_data);
103     if (!iostream)
104         return -1;
105
106     memset(&img, 0, sizeof(img));
107     memset(&callouts, 0, sizeof(callouts));
108     callouts.setup_f = imgDecodeSetup;
109     callouts.data = reinterpret_cast<_Uintptrt>(this);
110
111     int rc = img_load(s_ilib, iostream, &callouts, &img);
112     io_close(iostream);
113     if (rc != IMG_ERR_INTR)
114         return -1;
115     if (!m_width || !m_height)
116         return -1;
117
118     width = m_width;
119     height = m_height;
120
121     return 0;
122 }
123
124 int ImageReader::decode(size_t width, size_t height, ImageFrame* aFrame)
125 {
126     if (libInit() == -1)
127         return -1;
128
129     img_t img;
130     memset(&img, 0, sizeof(img));
131     img.format = IMG_FMT_RGB888;
132     img.w = width;
133     img.h = height;
134
135     const int ColorComponents = 3;
136     // Use a multiple of 2 bytes to improve performance
137     int stride = (ColorComponents * width + 3) & ~3;
138     OwnArrayPtr<_uint8> buffer = adoptArrayPtr(new _uint8[stride * height]);
139     if (!buffer)
140         return -1;
141     img.access.direct.data = buffer.get();
142     img.access.direct.stride = stride;
143     img.flags = IMG_W | IMG_H | IMG_DIRECT | IMG_FORMAT;
144
145     io_stream_t* iostream = io_open(IO_MEM, IO_READ, m_size, m_data);
146     if (!iostream)
147         return -1;
148
149     int rc = img_load_resize(s_ilib, iostream, 0, &img);
150     io_close(iostream);
151     if (rc != IMG_ERR_OK)
152         return -1;
153
154     for (unsigned j = 0; j < height; j++) {
155         _uint8* curPtr = buffer.get() + j * stride;
156         for (unsigned i = 0; i < width; i++) {
157             aFrame->setRGBA(i, j, curPtr[0], curPtr[1], curPtr[2], 255);
158             curPtr += 3;
159         }
160     }
161     return 0;
162 }
163
164 JPEGImageDecoder::JPEGImageDecoder(ImageSource::AlphaOption alphaOption,
165                                    ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
166     : ImageDecoder(alphaOption, gammaAndColorProfileOption)
167 {
168 }
169
170 void JPEGImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
171 {
172     ImageDecoder::setData(data, allDataReceived);
173
174     if (m_reader)
175         m_reader->updateData(m_data->data(), m_data->size());
176 }
177
178 bool JPEGImageDecoder::isSizeAvailable()
179 {
180     if (!ImageDecoder::isSizeAvailable()) {
181         if (!m_reader) {
182             if (m_data)
183                 m_reader = adoptPtr(new ImageReader(m_data->data(), m_data->size()));
184             if (!m_reader)
185                 return false;
186         }
187         size_t width, height;
188
189         if (m_reader->sizeExtract(width, height) == -1)
190             return false;
191         if (!setSize(width, height))
192             return false;
193     }
194
195     return ImageDecoder::isSizeAvailable();
196 }
197
198 ImageFrame* JPEGImageDecoder::frameBufferAtIndex(size_t index)
199 {
200     if (!isAllDataReceived())
201         return 0;
202
203     if (index)
204         return 0;
205
206     if (m_frameBufferCache.isEmpty())
207         m_frameBufferCache.resize(1);
208
209     ImageFrame& frame = m_frameBufferCache[0];
210
211     // Check to see if it's already decoded.
212     // FIXME: Could size change between calls to this method?
213     if (frame.status() == ImageFrame::FrameComplete)
214         return &frame;
215
216     if (frame.status() == ImageFrame::FrameEmpty) {
217         if (!size().width() || !size().height()) {
218             if (!isSizeAvailable())
219                 return 0;
220         }
221         if (!frame.setSize(size().width(), size().height())) {
222             setFailed();
223             return 0;
224         }
225         frame.setStatus(ImageFrame::FramePartial);
226         // For JPEGs, the frame always fills the entire image.
227         frame.setOriginalFrameRect(IntRect(IntPoint(), size()));
228     }
229
230     if (!m_reader || m_reader->decode(size().width(), size().height(), &frame) == -1) {
231         setFailed();
232         return 0;
233     }
234
235     frame.setStatus(ImageFrame::FrameComplete);
236     return &frame;
237 }
238
239 } // namespace WebCore
240