don't discard iframe children.
[kdelibs.git] / khtml / misc / loader_jpeg.cpp
blob8af54df20cacbc2e0eaef72f111ccd0f0e517b5b
1 /*
2 This file is part of the KDE libraries
4 Copyright (C) 2000 Dirk Mueller (mueller@kde.org)
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 #include "loader_jpeg.h"
27 #include <config.h>
29 #ifdef HAVE_LIBJPEG
30 // on some systems, libjpeg installs its config.h file which causes a conflict
31 // and makes the compiler barf with "XXX already defined".
32 #ifdef HAVE_STDLIB_H
33 #undef HAVE_STDLIB_H
34 #endif
36 #include <stdio.h>
37 #include <setjmp.h>
38 #include <qdatetime.h>
39 #include <kglobal.h>
40 #include <qrect.h>
42 extern "C" {
43 #define XMD_H
44 #include <jpeglib.h>
45 #undef const
49 #undef BUFFER_DEBUG
50 //#define BUFFER_DEBUG
52 #undef JPEG_DEBUG
53 //#define JPEG_DEBUG
55 // -----------------------------------------------------------------------------
57 struct khtml_error_mgr : public jpeg_error_mgr {
58 jmp_buf setjmp_buffer;
61 extern "C" {
63 static
64 void khtml_error_exit (j_common_ptr cinfo)
66 khtml_error_mgr* myerr = (khtml_error_mgr*) cinfo->err;
67 char buffer[JMSG_LENGTH_MAX];
68 (*cinfo->err->format_message)(cinfo, buffer);
69 #ifdef JPEG_DEBUG
70 qWarning("%s", buffer);
71 #endif
72 longjmp(myerr->setjmp_buffer, 1);
76 static const int max_buf = 32768;
77 static const int max_consumingtime = 2000;
79 struct khtml_jpeg_source_mgr : public jpeg_source_mgr {
80 JOCTET buffer[max_buf];
82 int valid_buffer_len;
83 size_t skip_input_bytes;
84 int ateof;
85 QRect change_rect;
86 QRect old_change_rect;
87 QTime decoder_timestamp;
88 bool final_pass;
89 bool decoding_done;
90 bool do_progressive;
92 public:
93 khtml_jpeg_source_mgr() KDE_NO_EXPORT;
97 extern "C" {
99 static
100 void khtml_j_decompress_dummy(j_decompress_ptr)
104 static
105 boolean khtml_fill_input_buffer(j_decompress_ptr cinfo)
107 #ifdef BUFFER_DEBUG
108 qDebug("khtml_fill_input_buffer called!");
109 #endif
111 khtml_jpeg_source_mgr* src = (khtml_jpeg_source_mgr*)cinfo->src;
113 if ( src->ateof )
115 /* Insert a fake EOI marker - as per jpeglib recommendation */
116 src->buffer[0] = (JOCTET) 0xFF;
117 src->buffer[1] = (JOCTET) JPEG_EOI;
118 src->bytes_in_buffer = 2;
119 src->next_input_byte = (JOCTET *) src->buffer;
120 #ifdef BUFFER_DEBUG
121 qDebug("...returning true!");
122 #endif
123 return true;
125 else
126 return false; /* I/O suspension mode */
129 static
130 void khtml_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
132 if(num_bytes <= 0)
133 return; /* required noop */
135 #ifdef BUFFER_DEBUG
136 qDebug("khtml_skip_input_data (%d) called!", num_bytes);
137 #endif
139 khtml_jpeg_source_mgr* src = (khtml_jpeg_source_mgr*)cinfo->src;
140 src->skip_input_bytes += num_bytes;
142 unsigned int skipbytes = qMin(src->bytes_in_buffer, src->skip_input_bytes);
144 #ifdef BUFFER_DEBUG
145 qDebug("skip_input_bytes is now %d", src->skip_input_bytes);
146 qDebug("skipbytes is now %d", skipbytes);
147 qDebug("valid_buffer_len is before %d", src->valid_buffer_len);
148 qDebug("bytes_in_buffer is %d", src->bytes_in_buffer);
149 #endif
151 if(skipbytes < src->bytes_in_buffer)
152 memmove(src->buffer, src->next_input_byte+skipbytes, src->bytes_in_buffer - skipbytes);
154 src->bytes_in_buffer -= skipbytes;
155 src->valid_buffer_len = src->bytes_in_buffer;
156 src->skip_input_bytes -= skipbytes;
158 /* adjust data for jpeglib */
159 cinfo->src->next_input_byte = (JOCTET *) src->buffer;
160 cinfo->src->bytes_in_buffer = (size_t) src->valid_buffer_len;
161 #ifdef BUFFER_DEBUG
162 qDebug("valid_buffer_len is afterwards %d", src->valid_buffer_len);
163 qDebug("skip_input_bytes is now %d", src->skip_input_bytes);
164 #endif
169 khtml_jpeg_source_mgr::khtml_jpeg_source_mgr()
171 jpeg_source_mgr::init_source = khtml_j_decompress_dummy;
172 jpeg_source_mgr::fill_input_buffer = khtml_fill_input_buffer;
173 jpeg_source_mgr::skip_input_data = khtml_skip_input_data;
174 jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart;
175 jpeg_source_mgr::term_source = khtml_j_decompress_dummy;
176 bytes_in_buffer = 0;
177 valid_buffer_len = 0;
178 skip_input_bytes = 0;
179 ateof = 0;
180 next_input_byte = buffer;
181 final_pass = false;
182 decoding_done = false;
187 // -----------------------------------------------------------------------------
189 #if 0 // TODO: wait
190 class KJPEGFormat : public QImageFormat
192 public:
193 KJPEGFormat();
195 virtual ~KJPEGFormat();
197 virtual int decode(QImage& img, QImageConsumer* consumer,
198 const uchar* buffer, int length);
199 private:
201 enum {
202 Init,
203 readHeader,
204 startDecompress,
205 decompressStarted,
206 consumeInput,
207 prepareOutputScan,
208 doOutputScan,
209 readDone,
210 invalid
211 } state;
213 // structs for the jpeglib
214 struct jpeg_decompress_struct cinfo;
215 struct khtml_error_mgr jerr;
216 struct khtml_jpeg_source_mgr jsrc;
220 // -----------------------------------------------------------------------------
222 KJPEGFormat::KJPEGFormat()
224 memset(&cinfo, 0, sizeof(cinfo));
225 cinfo.err = jpeg_std_error(&jerr);
226 jpeg_create_decompress(&cinfo);
227 cinfo.err = jpeg_std_error(&jerr);
228 jerr.error_exit = khtml_error_exit;
229 cinfo.src = &jsrc;
230 state = Init;
234 KJPEGFormat::~KJPEGFormat()
236 (void) jpeg_destroy_decompress(&cinfo);
240 * return > 0 means "consumed x bytes, need more"
241 * return == 0 means "end of frame reached"
242 * return < 0 means "fatal error in image decoding, don't call me ever again"
245 int KJPEGFormat::decode(QImage& image, QImageConsumer* consumer, const uchar* buffer, int length)
247 #ifdef JPEG_DEBUG
248 qDebug("KJPEGFormat::decode(%08lx, %08lx, %08lx, %d)",
249 &image, consumer, buffer, length);
250 #endif
252 if(jsrc.ateof) {
253 #ifdef JPEG_DEBUG
254 qDebug("ateof, eating");
255 #endif
256 return length;
260 if(setjmp(jerr.setjmp_buffer))
262 #ifdef JPEG_DEBUG
263 qDebug("jump into state invalid");
264 #endif
265 if(consumer)
266 consumer->end();
268 // this is fatal
269 return -1;
272 int consumed = qMin(length, max_buf - jsrc.valid_buffer_len);
274 #ifdef BUFFER_DEBUG
275 qDebug("consuming %d bytes", consumed);
276 #endif
278 // filling buffer with the new data
279 memcpy(jsrc.buffer + jsrc.valid_buffer_len, buffer, consumed);
280 jsrc.valid_buffer_len += consumed;
282 if(jsrc.skip_input_bytes)
284 #ifdef BUFFER_DEBUG
285 qDebug("doing skipping");
286 qDebug("valid_buffer_len %d", jsrc.valid_buffer_len);
287 qDebug("skip_input_bytes %d", jsrc.skip_input_bytes);
288 #endif
289 int skipbytes = qMin((size_t) jsrc.valid_buffer_len, jsrc.skip_input_bytes);
291 if(skipbytes < jsrc.valid_buffer_len)
292 memmove(jsrc.buffer, jsrc.buffer+skipbytes, jsrc.valid_buffer_len - skipbytes);
294 jsrc.valid_buffer_len -= skipbytes;
295 jsrc.skip_input_bytes -= skipbytes;
297 // still more bytes to skip
298 if(jsrc.skip_input_bytes) {
299 if(consumed <= 0) qDebug("ERROR!!!");
300 return consumed;
305 cinfo.src->next_input_byte = (JOCTET *) jsrc.buffer;
306 cinfo.src->bytes_in_buffer = (size_t) jsrc.valid_buffer_len;
308 #ifdef BUFFER_DEBUG
309 qDebug("buffer contains %d bytes", jsrc.valid_buffer_len);
310 #endif
312 if(state == Init)
314 if(jpeg_read_header(&cinfo, true) != JPEG_SUSPENDED) {
315 // do some simple memory requirements limitations
316 // as long as we use that stupid Qt stuff
317 int s = cinfo.image_width * cinfo.image_height;
318 if ( s > 16384 * 12388 )
319 cinfo.scale_denom = 8;
320 else if ( s > 8192 * 6144 )
321 cinfo.scale_denom = 4;
322 else if ( s > 4096 * 3072 )
323 cinfo.scale_denom = 2;
325 if ( consumer )
326 consumer->setSize(cinfo.image_width/cinfo.scale_denom,
327 cinfo.image_height/cinfo.scale_denom);
329 state = startDecompress;
333 if(state == startDecompress)
335 jsrc.do_progressive = jpeg_has_multiple_scans( &cinfo );
337 #ifdef JPEG_DEBUG
338 qDebug( "**** DOPROGRESSIVE: %d", jsrc.do_progressive );
339 #endif
340 if ( jsrc.do_progressive )
341 cinfo.buffered_image = true;
342 else
343 cinfo.buffered_image = false;
345 // setup image sizes
346 jpeg_calc_output_dimensions( &cinfo );
348 if ( cinfo.jpeg_color_space == JCS_YCbCr )
349 cinfo.out_color_space = JCS_RGB;
351 cinfo.do_fancy_upsampling = true;
352 cinfo.do_block_smoothing = false;
353 cinfo.quantize_colors = false;
355 // false: IO suspension
356 if(jpeg_start_decompress(&cinfo)) {
357 if ( cinfo.output_components == 3 || cinfo.output_components == 4) {
358 image.create( cinfo.output_width, cinfo.output_height, 32 );
359 } else if ( cinfo.output_components == 1 ) {
360 image.create( cinfo.output_width, cinfo.output_height, 8, 256 );
361 for (int i=0; i<256; i++)
362 image.setColor(i, qRgb(i,i,i));
365 #ifdef JPEG_DEBUG
366 qDebug("will create a picture %d/%d in size", cinfo.output_width, cinfo.output_height);
367 #endif
369 #ifdef JPEG_DEBUG
370 qDebug("ok, going to decompressStarted");
371 #endif
373 jsrc.decoder_timestamp.start();
374 state = jsrc.do_progressive ? decompressStarted : doOutputScan;
378 again:
380 if(state == decompressStarted) {
381 state = (!jsrc.final_pass && jsrc.decoder_timestamp.elapsed() < max_consumingtime)
382 ? consumeInput : prepareOutputScan;
385 if(state == consumeInput)
387 int retval;
389 do {
390 retval = jpeg_consume_input(&cinfo);
391 } while (retval != JPEG_SUSPENDED && retval != JPEG_REACHED_EOI
392 && (retval != JPEG_REACHED_SOS || jsrc.decoder_timestamp.elapsed() < max_consumingtime));
394 if(jsrc.decoder_timestamp.elapsed() >= max_consumingtime ||
395 jsrc.final_pass ||
396 retval == JPEG_REACHED_EOI || retval == JPEG_REACHED_SOS)
397 state = prepareOutputScan;
400 if(state == prepareOutputScan)
402 if ( jpeg_start_output(&cinfo, cinfo.input_scan_number) )
403 state = doOutputScan;
406 if(state == doOutputScan)
408 if(image.isNull() || jsrc.decoding_done)
410 #ifdef JPEG_DEBUG
411 qDebug("complete in doOutputscan, eating..");
412 #endif
413 return consumed;
415 uchar** lines = image.jumpTable();
416 int oldoutput_scanline = cinfo.output_scanline;
418 while(cinfo.output_scanline < cinfo.output_height &&
419 jpeg_read_scanlines(&cinfo, lines+cinfo.output_scanline, cinfo.output_height))
420 ; // here happens all the magic of decoding
422 int completed_scanlines = cinfo.output_scanline - oldoutput_scanline;
423 #ifdef JPEG_DEBUG
424 qDebug("completed now %d scanlines", completed_scanlines);
425 #endif
427 if ( cinfo.output_components == 3 ) {
428 // Expand 24->32 bpp.
429 for (int j=oldoutput_scanline; j<oldoutput_scanline+completed_scanlines; j++) {
430 uchar *in = image.scanLine(j) + cinfo.output_width * 3;
431 QRgb *out = (QRgb*)image.scanLine(j);
433 for (uint i=cinfo.output_width; i--; ) {
434 in-=3;
435 out[i] = qRgb(in[0], in[1], in[2]);
440 if(consumer && completed_scanlines)
442 QRect r(0, oldoutput_scanline, cinfo.output_width, completed_scanlines);
443 #ifdef JPEG_DEBUG
444 qDebug("changing %d/%d %d/%d", r.x(), r.y(), r.width(), r.height());
445 #endif
446 jsrc.change_rect |= r;
448 if ( jsrc.decoder_timestamp.elapsed() >= max_consumingtime ) {
449 if( !jsrc.old_change_rect.isEmpty()) {
450 consumer->changed(jsrc.old_change_rect);
451 jsrc.old_change_rect = QRect();
453 consumer->changed(jsrc.change_rect);
454 jsrc.change_rect = QRect();
455 jsrc.decoder_timestamp.restart();
459 if(cinfo.output_scanline >= cinfo.output_height)
461 if ( jsrc.do_progressive ) {
462 jpeg_finish_output(&cinfo);
463 jsrc.final_pass = jpeg_input_complete(&cinfo);
464 jsrc.decoding_done = jsrc.final_pass && cinfo.input_scan_number == cinfo.output_scan_number;
465 if ( !jsrc.decoding_done ) {
466 jsrc.old_change_rect |= jsrc.change_rect;
467 jsrc.change_rect = QRect();
470 else
471 jsrc.decoding_done = true;
473 #ifdef JPEG_DEBUG
474 qDebug("one pass is completed, final_pass = %d, dec_done: %d, complete: %d",
475 jsrc.final_pass, jsrc.decoding_done, jpeg_input_complete(&cinfo));
476 #endif
477 if(!jsrc.decoding_done)
479 #ifdef JPEG_DEBUG
480 qDebug("starting another one, input_scan_number is %d/%d", cinfo.input_scan_number,
481 cinfo.output_scan_number);
482 #endif
483 jsrc.decoder_timestamp.restart();
484 state = decompressStarted;
485 // don't return until necessary!
486 goto again;
490 if(state == doOutputScan && jsrc.decoding_done) {
491 #ifdef JPEG_DEBUG
492 qDebug("input is complete, cleaning up, returning..");
493 #endif
494 if ( consumer && !jsrc.change_rect.isEmpty() )
495 consumer->changed( jsrc.change_rect );
497 if(consumer)
498 consumer->end();
500 jsrc.ateof = true;
502 (void) jpeg_finish_decompress(&cinfo);
503 (void) jpeg_destroy_decompress(&cinfo);
505 state = readDone;
507 return 0;
511 #ifdef BUFFER_DEBUG
512 qDebug("valid_buffer_len is now %d", jsrc.valid_buffer_len);
513 qDebug("bytes_in_buffer is now %d", jsrc.bytes_in_buffer);
514 qDebug("consumed %d bytes", consumed);
515 #endif
516 if(jsrc.bytes_in_buffer && jsrc.buffer != jsrc.next_input_byte)
517 memmove(jsrc.buffer, jsrc.next_input_byte, jsrc.bytes_in_buffer);
518 jsrc.valid_buffer_len = jsrc.bytes_in_buffer;
519 return consumed;
522 // -----------------------------------------------------------------------------
523 // This is the factory that teaches Qt about progressive JPEG's
525 QImageFormat* khtml::KJPEGFormatType::decoderFor(const unsigned char* buffer, int length)
527 if(length < 3) return 0;
529 if(buffer[0] == 0377 &&
530 buffer[1] == 0330 &&
531 buffer[2] == 0377)
532 return new KJPEGFormat;
534 return 0;
537 const char* khtml::KJPEGFormatType::formatName() const
539 return "JPEG";
542 #endif
544 #else
545 #ifdef __GNUC__
546 #warning You don't seem to have libJPEG. jpeg support in khtml won't work
547 #endif
548 #endif // HAVE_LIBJPEG
550 // -----------------------------------------------------------------------------