1/*
2 * Copyright (C) 2012 Company 100 Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "ParallelImageDecoder.h"
28
29#include <wtf/MainThread.h>
30#include <wtf/OwnArrayPtr.h>
31#include <wtf/OwnPtr.h>
32#include <wtf/PassOwnArrayPtr.h>
33#include <wtf/PassOwnPtr.h>
34
35namespace WebCore {
36
37struct ParallelFrameData;
38void didDecodeTaskCallback(ParallelFrameData*);
39static ImageFrameData createImageFrameData(ParallelFrameData*);
40
41ParallelImageDecoder::ParallelImageDecoder(ParallelImageDecoderObserver* observer, ImageDecoder* decoder)
42 : m_observer(observer)
43 , m_isAllDataReceived(false)
44 , m_bytesOfDataConsumed(0)
45 , m_imageDecoder(0)
46{
47 initialize(decoder);
48}
49
50ParallelImageDecoder::~ParallelImageDecoder()
51{
52 ASSERT(!valid());
53}
54
55void ParallelImageDecoder::initialize(ImageDecoder* decoder)
56{
57 ASSERT(isMainThread());
58 ASSERT(decoder->isSizeAvailable() && !decoder->size().isEmpty());
59
60 m_size = decoder->size();
61 m_filenameExtension = decoder->filenameExtension();
62
63 setData(decoder->data(), decoder->isAllDataReceived());
64 m_bytesOfDataConsumed = 0;
65
66 m_imageFrame.setSize(m_size.width(), m_size.height());
67
68 m_imageDecoder = decoder;
69 m_imageDecoder->setData(0, false);
70 // After this line, it is illegal for the main thread to access m_imageDecoder.
71
72 // This must be the last line because ImageDecodeWorker guarantees
73 // the visibility of members in the task thread.
74 m_decodeWorker = ImageDecodeWorker::acquireSharedWorker();
75}
76
77void ParallelImageDecoder::invalidate()
78{
79 ASSERT(isMainThread());
80 ASSERT(m_imageDecoder);
81
82 m_decodeWorker.clear();
83 // The main thread can use m_imageDecoder because other threads do not access m_imageDecoder after this line.
84
85 m_imageDecoder->setData(m_data.get(), m_isAllDataReceived);
86
87 m_size = IntSize();
88 m_filenameExtension = "";
89
90 m_isAllDataReceived = false;
91 m_data.clear();
92 m_bytesOfDataConsumed = 0;
93
94 m_imageFrame = ImageFrame();
95
96 if (m_dataForTask.get())
97 m_dataForTask.clear();
98
99 m_imageDecoder = 0;
100}
101
102void ParallelImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
103{
104 ASSERT(isMainThread());
105 m_isAllDataReceived = allDataReceived;
106 m_data = data;
107}
108
109void ParallelImageDecoder::decode()
110{
111 ASSERT(isMainThread());
112 ASSERT(m_imageDecoder);
113 ASSERT(!m_size.isEmpty());
114
115 OwnPtr<EncodedDataSegment> segment = extractSegmentForTask();
116 if (!segment.get())
117 return;
118 m_decodeWorker->postTask(bind(&ParallelImageDecoder::decodeTask, this, segment.release()));
119}
120
121PassOwnPtr<ParallelImageDecoder::EncodedDataSegment> ParallelImageDecoder::extractSegmentForTask()
122{
123 ASSERT(m_bytesOfDataConsumed >= 0 && m_bytesOfDataConsumed <= m_data->size());
124
125 int sizeOfSegment = m_data->size() - m_bytesOfDataConsumed;
126 if (!sizeOfSegment)
127 return PassOwnPtr<EncodedDataSegment>();
128
129 OwnPtr<EncodedDataSegment> segment(adoptPtr(new EncodedDataSegment()));
130 const char* srcPtr = m_data->data() + m_bytesOfDataConsumed;
131 segment->m_segment.append(srcPtr, sizeOfSegment);
132 m_bytesOfDataConsumed = m_data->size();
133
134 segment->m_isAllDataReceived = m_isAllDataReceived;
135
136 return segment.release();
137}
138
139struct ParallelFrameData {
140 WTF_MAKE_NONCOPYABLE(ParallelFrameData);
141 WTF_MAKE_FAST_ALLOCATED;
142public:
143 explicit ParallelFrameData(PassRefPtr<ParallelImageDecoder> parallelDecoder)
144 : m_parallelDecoder(parallelDecoder)
145 , m_decodedSegment()
146 , m_status(ImageFrame::FrameEmpty)
147 , m_hasAlpha(false)
148 , m_premultiplyAlpha(true)
149 {
150 }
151
152 ~ParallelFrameData()
153 {
154 }
155
156 RefPtr<ParallelImageDecoder> m_parallelDecoder;
157 OwnArrayPtr<ImageFrame::PixelData> m_decodedSegment;
158 ImageFrame::FrameStatus m_status;
159 bool m_hasAlpha;
160 bool m_premultiplyAlpha;
161 IntRect m_decodedRect;
162};
163
164void ParallelImageDecoder::decodeTask(PassOwnPtr<ParallelImageDecoder::EncodedDataSegment> passSegment)
165{
166 ASSERT(!isMainThread());
167 ASSERT(m_imageDecoder);
168
169 OwnPtr<EncodedDataSegment> segment = passSegment;
170
171 // 1. Send segment data to ImageDecoder.
172 if (!m_dataForTask) {
173 m_dataForTask = SharedBuffer::create();
174#ifndef NDEBUG
175 // ThreadRestrictionVerifier does not allow two threads to access one RefCounted object.
176 // m_dataForTask is used by both the main thread and the task thread:
177 // The task thread creates, uses and removes m_dataForTask. The main thread may remove
178 // m_dataForTask if the task thread could not remove m_dataForTask.
179 //
180 // Parallel image decoders manage m_dataForTask in a thread-safe way. However,
181 // we can't tell the verifier that we are safe by simply passing a mutex
182 // because libdispatch does not even guarantee decodeTask is called by the same thread
183 // each time. So turn off the verifier here.
184 m_dataForTask->turnOffVerifier();
185#endif
186 }
187 m_dataForTask->append(segment->m_segment);
188 m_imageDecoder->setData(m_dataForTask.get(), segment->m_isAllDataReceived);
189
190 ImageFrame* oldBuffer = m_imageDecoder->firstImageFrameWithoutDecode();
191 int lastDecodedRow = oldBuffer ? oldBuffer->lastDecodedRow() : 0;
192
193 // 2. Decode an image incrementally.
194 ImageFrame* buffer = m_imageDecoder->frameBufferAtIndex(0);
195 if (!buffer || buffer->status() == ImageFrame::FrameEmpty) {
196 ASSERT(!segment->m_isAllDataReceived);
197 return;
198 }
199
200 // 3. Make a ParallelFrameData in order to pass it to the main thread.
201 ParallelFrameData* parallelFrameData = new ParallelFrameData(this);
202 parallelFrameData->m_status = buffer->status();
203 parallelFrameData->m_hasAlpha = buffer->hasAlpha();
204 parallelFrameData->m_premultiplyAlpha = buffer->premultiplyAlpha();
205
206 int newLastDecodedRow = buffer->lastDecodedRow();
207 // Only in BMP, lastDecodedRow can be bigger than newLastDecodedRow.
208 int lastDecodedMinRow = std::min(lastDecodedRow, newLastDecodedRow);
209 int lastDecodedMaxRow = std::max(lastDecodedRow, newLastDecodedRow);
210 parallelFrameData->m_decodedRect = IntRect(0, lastDecodedMinRow, m_imageDecoder->size().width(), lastDecodedMaxRow - lastDecodedMinRow + 1);
211
212 // 4. Create decoded segment data in order to pass it to the main thread.
213 // If the status is FrameComplete, this is not needed because a NativeImage will be created using the decoder on the main thread.
214 if (parallelFrameData->m_status == ImageFrame::FramePartial) {
215 int segmentSize = parallelFrameData->m_decodedRect.size().area();
216 parallelFrameData->m_decodedSegment = adoptArrayPtr(new ImageFrame::PixelData[segmentSize]);
217
218 ImageFrame::PixelData* segmentAddr = parallelFrameData->m_decodedSegment.get();
219 memcpy(segmentAddr, buffer->getAddr(0, lastDecodedMinRow), segmentSize * sizeof(ImageFrame::PixelData));
220 } else { // FrameComplete
221 m_imageDecoder->setData(0, false);
222 m_dataForTask.clear();
223 }
224
225 callOnMainThread(bind(didDecodeTaskCallback, parallelFrameData));
226}
227
228void didDecodeTaskCallback(ParallelFrameData* parallelFrameData)
229{
230 ASSERT(isMainThread());
231 // If a client called ParallelImageDecoder::clear(), ParallelImageDecoder is invalidated.
232 if (parallelFrameData->m_parallelDecoder->valid())
233 parallelFrameData->m_parallelDecoder->didDecodeTask(parallelFrameData);
234 delete parallelFrameData;
235}
236
237ImageFrameData createImageFrameData(ParallelFrameData* parallelFrameData)
238{
239 ImageFrameData imageFrameData;
240 imageFrameData.m_orientation = DefaultImageOrientation;
241 imageFrameData.m_isComplete = parallelFrameData->m_status == ImageFrame::FrameComplete;
242 imageFrameData.m_hasAlpha = !imageFrameData.m_isComplete || parallelFrameData->m_hasAlpha;
243 return imageFrameData;
244}
245
246void ParallelImageDecoder::didDecodeTask(ParallelFrameData* parallelFrameData)
247{
248 ASSERT(isMainThread());
249 ASSERT(parallelFrameData->m_status != ImageFrame::FrameEmpty);
250
251 ImageFrameData imageFrameData = createImageFrameData(parallelFrameData);
252
253 if (!imageFrameData.m_isComplete)
254 didDecodePartial(imageFrameData, parallelFrameData);
255 else
256 didDecodeComplete(imageFrameData);
257}
258
259void ParallelImageDecoder::didDecodePartial(ImageFrameData& imageFrameData, ParallelFrameData* parallelFrameData)
260{
261 ASSERT(isMainThread());
262
263 appendDecodedDataToImageFrame(parallelFrameData);
264 syncImageFrame(parallelFrameData);
265
266 imageFrameData.m_frame = m_imageFrame.asNewNativeImage();
267 m_observer->didDecode(imageFrameData);
268}
269
270void ParallelImageDecoder::appendDecodedDataToImageFrame(ParallelFrameData* parallelFrameData)
271{
272 const ImageFrame::PixelData* const segmentAddr = parallelFrameData->m_decodedSegment.get();
273 int segmentSize = parallelFrameData->m_decodedRect.size().area();
274 ImageFrame::PixelData* destAddr = m_imageFrame.getAddr(0, parallelFrameData->m_decodedRect.y());
275 memcpy(destAddr, segmentAddr, segmentSize * sizeof(ImageFrame::PixelData));
276}
277
278void ParallelImageDecoder::syncImageFrame(ParallelFrameData* parallelFrameData)
279{
280 // The following lines are needed to create a valid native image in ImageFrame::asNewNativeImage().
281 m_imageFrame.setStatus(parallelFrameData->m_status);
282 m_imageFrame.setHasAlpha(parallelFrameData->m_hasAlpha);
283 m_imageFrame.setPremultiplyAlpha(parallelFrameData->m_premultiplyAlpha);
284}
285
286void ParallelImageDecoder::didDecodeComplete(ImageFrameData& imageFrameData)
287{
288 ASSERT(isMainThread());
289
290 m_decodeWorker.clear();
291 // The main thread can use m_imageDecoder because other threads do not access m_imageDecoder after this line.
292
293 ImageFrame* buffer = m_imageDecoder->firstImageFrameWithoutDecode();
294 ASSERT(buffer);
295
296 imageFrameData.m_frame = buffer->asNewNativeImage();
297 m_observer->didDecode(imageFrameData);
298}
299
300}