Fix loop count in animanted gifs sometimes being incorrect
[qt:qt.git] / src / gui / image / qgifhandler.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the plugins of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ** WARNING:
41 **      A separate license from Unisys may be required to use the gif
42 **      reader. See http://www.unisys.com/about__unisys/lzw/
43 **      for information from Unisys
44 **
45 ****************************************************************************/
46
47 #include "qgifhandler_p.h"
48
49 #include <qimage.h>
50 #include <qiodevice.h>
51 #include <qvariant.h>
52
53 QT_BEGIN_NAMESPACE
54
55 #define Q_TRANSPARENT 0x00ffffff
56
57 // avoid going through QImage::scanLine() which calls detach
58 #define FAST_SCAN_LINE(bits, bpl, y) (bits + (y) * bpl)
59
60
61 /*
62   Incremental image decoder for GIF image format.
63
64   This subclass of QImageFormat decodes GIF format images,
65   including animated GIFs. Internally in
66 */
67
68 class QGIFFormat {
69 public:
70     QGIFFormat();
71     ~QGIFFormat();
72
73     int decode(QImage *image, const uchar* buffer, int length,
74                int *nextFrameDelay, int *loopCount);
75     static void scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount);
76
77     bool newFrame;
78     bool partialNewFrame;
79
80 private:
81     void fillRect(QImage *image, int x, int y, int w, int h, QRgb col);
82     inline QRgb color(uchar index) const;
83
84     // GIF specific stuff
85     QRgb* globalcmap;
86     QRgb* localcmap;
87     QImage backingstore;
88     unsigned char hold[16];
89     bool gif89;
90     int count;
91     int ccount;
92     int expectcount;
93     enum State {
94         Header,
95         LogicalScreenDescriptor,
96         GlobalColorMap,
97         LocalColorMap,
98         Introducer,
99         ImageDescriptor,
100         TableImageLZWSize,
101         ImageDataBlockSize,
102         ImageDataBlock,
103         ExtensionLabel,
104         GraphicControlExtension,
105         ApplicationExtension,
106         NetscapeExtensionBlockSize,
107         NetscapeExtensionBlock,
108         SkipBlockSize,
109         SkipBlock,
110         Done,
111         Error
112     } state;
113     int gncols;
114     int lncols;
115     int ncols;
116     int lzwsize;
117     bool lcmap;
118     int swidth, sheight;
119     int width, height;
120     int left, top, right, bottom;
121     enum Disposal { NoDisposal, DoNotChange, RestoreBackground, RestoreImage };
122     Disposal disposal;
123     bool disposed;
124     int trans_index;
125     bool gcmap;
126     int bgcol;
127     int interlace;
128     int accum;
129     int bitcount;
130
131     enum { max_lzw_bits=12 }; // (poor-compiler's static const int)
132
133     int code_size, clear_code, end_code, max_code_size, max_code;
134     int firstcode, oldcode, incode;
135     short* table[2];
136     short* stack;
137     short *sp;
138     bool needfirst;
139     int x, y;
140     int frame;
141     bool out_of_bounds;
142     bool digress;
143     void nextY(unsigned char *bits, int bpl);
144     void disposePrevious(QImage *image);
145 };
146
147 /*!
148     Constructs a QGIFFormat.
149 */
150 QGIFFormat::QGIFFormat()
151 {
152     globalcmap = 0;
153     localcmap = 0;
154     lncols = 0;
155     gncols = 0;
156     disposal = NoDisposal;
157     out_of_bounds = false;
158     disposed = true;
159     frame = -1;
160     state = Header;
161     count = 0;
162     lcmap = false;
163     newFrame = false;
164     partialNewFrame = false;
165     table[0] = 0;
166     table[1] = 0;
167     stack = 0;
168 }
169
170 /*!
171     Destroys a QGIFFormat.
172 */
173 QGIFFormat::~QGIFFormat()
174 {
175     if (globalcmap) delete[] globalcmap;
176     if (localcmap) delete[] localcmap;
177     delete [] stack;
178 }
179
180 void QGIFFormat::disposePrevious(QImage *image)
181 {
182     if (out_of_bounds) {
183         // flush anything that survived
184         // ### Changed: QRect(0, 0, swidth, sheight)
185     }
186
187     // Handle disposal of previous image before processing next one
188
189     if (disposed) return;
190
191     int l = qMin(swidth-1,left);
192     int r = qMin(swidth-1,right);
193     int t = qMin(sheight-1,top);
194     int b = qMin(sheight-1,bottom);
195
196     switch (disposal) {
197       case NoDisposal:
198         break;
199       case DoNotChange:
200         break;
201       case RestoreBackground:
202         if (trans_index>=0) {
203             // Easy:  we use the transparent color
204             fillRect(image, l, t, r-l+1, b-t+1, Q_TRANSPARENT);
205         } else if (bgcol>=0) {
206             // Easy:  we use the bgcol given
207             fillRect(image, l, t, r-l+1, b-t+1, color(bgcol));
208         } else {
209             // Impossible:  We don't know of a bgcol - use pixel 0
210             QRgb *bits = (QRgb*)image->bits();
211             fillRect(image, l, t, r-l+1, b-t+1, bits[0]);
212         }
213         // ### Changed: QRect(l, t, r-l+1, b-t+1)
214         break;
215       case RestoreImage: {
216         if (frame >= 0) {
217             for (int ln=t; ln<=b; ln++) {
218                 memcpy(image->scanLine(ln)+l,
219                     backingstore.scanLine(ln-t),
220                     (r-l+1)*sizeof(QRgb));
221             }
222             // ### Changed: QRect(l, t, r-l+1, b-t+1)
223         }
224       }
225     }
226     disposal = NoDisposal; // Until an extension says otherwise.
227
228     disposed = true;
229 }
230
231 /*!
232     This function decodes some data into image changes.
233
234     Returns the number of bytes consumed.
235 */
236 int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
237                        int *nextFrameDelay, int *loopCount)
238 {
239     // We are required to state that
240     //    "The Graphics Interchange Format(c) is the Copyright property of
241     //    CompuServe Incorporated. GIF(sm) is a Service Mark property of
242     //    CompuServe Incorporated."
243
244     if (!stack) {
245         stack = new short[(1 << max_lzw_bits) * 4];
246         table[0] = &stack[(1 << max_lzw_bits) * 2];
247         table[1] = &stack[(1 << max_lzw_bits) * 3];
248     }
249
250     image->detach();
251     int bpl = image->bytesPerLine();
252     unsigned char *bits = image->bits();
253
254 #define LM(l, m) (((m)<<8)|l)
255     digress = false;
256     const int initial = length;
257     while (!digress && length) {
258         length--;
259         unsigned char ch=*buffer++;
260         switch (state) {
261           case Header:
262             hold[count++]=ch;
263             if (count==6) {
264                 // Header
265                 gif89=(hold[3]!='8' || hold[4]!='7');
266                 state=LogicalScreenDescriptor;
267                 count=0;
268             }
269             break;
270           case LogicalScreenDescriptor:
271             hold[count++]=ch;
272             if (count==7) {
273                 // Logical Screen Descriptor
274                 swidth=LM(hold[0], hold[1]);
275                 sheight=LM(hold[2], hold[3]);
276                 gcmap=!!(hold[4]&0x80);
277                 //UNUSED: bpchan=(((hold[4]&0x70)>>3)+1);
278                 //UNUSED: gcmsortflag=!!(hold[4]&0x08);
279                 gncols=2<<(hold[4]&0x7);
280                 bgcol=(gcmap) ? hold[5] : -1;
281                 //aspect=hold[6] ? double(hold[6]+15)/64.0 : 1.0;
282
283                 trans_index = -1;
284                 count=0;
285                 ncols=gncols;
286                 if (gcmap) {
287                     ccount=0;
288                     state=GlobalColorMap;
289                     globalcmap = new QRgb[gncols+1]; // +1 for trans_index
290                     globalcmap[gncols] = Q_TRANSPARENT;
291                 } else {
292                     state=Introducer;
293                 }
294             }
295             break;
296           case GlobalColorMap: case LocalColorMap:
297             hold[count++]=ch;
298             if (count==3) {
299                 QRgb rgb = qRgb(hold[0], hold[1], hold[2]);
300                 if (state == LocalColorMap) {
301                     if (ccount < lncols)
302                         localcmap[ccount] =  rgb;
303                 } else {
304                     globalcmap[ccount] = rgb;
305                 }
306                 if (++ccount >= ncols) {
307                     if (state == LocalColorMap)
308                         state=TableImageLZWSize;
309                     else
310                         state=Introducer;
311                 }
312                 count=0;
313             }
314             break;
315           case Introducer:
316             hold[count++]=ch;
317             switch (ch) {
318               case ',':
319                 state=ImageDescriptor;
320                 break;
321               case '!':
322                 state=ExtensionLabel;
323                 break;
324               case ';':
325                   // ### Changed: QRect(0, 0, swidth, sheight)
326                 state=Done;
327                 break;
328               default:
329                 digress=true;
330                 // Unexpected Introducer - ignore block
331                 state=Error;
332             }
333             break;
334           case ImageDescriptor:
335             hold[count++]=ch;
336             if (count==10) {
337                 int newleft=LM(hold[1], hold[2]);
338                 int newtop=LM(hold[3], hold[4]);
339                 int newwidth=LM(hold[5], hold[6]);
340                 int newheight=LM(hold[7], hold[8]);
341
342                 // disbelieve ridiculous logical screen sizes,
343                 // unless the image frames are also large.
344                 if (swidth/10 > qMax(newwidth,200))
345                     swidth = -1;
346                 if (sheight/10 > qMax(newheight,200))
347                     sheight = -1;
348
349                 if (swidth <= 0)
350                     swidth = newleft + newwidth;
351                 if (sheight <= 0)
352                     sheight = newtop + newheight;
353
354                 QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32;
355                 if (image->isNull()) {
356                     (*image) = QImage(swidth, sheight, format);
357                     bpl = image->bytesPerLine();
358                     bits = image->bits();
359                     memset(bits, 0, image->byteCount());
360                 }
361
362                 disposePrevious(image);
363                 disposed = false;
364
365                 left = newleft;
366                 top = newtop;
367                 width = newwidth;
368                 height = newheight;
369
370                 right=qMax(0, qMin(left+width, swidth)-1);
371                 bottom=qMax(0, qMin(top+height, sheight)-1);
372                 lcmap=!!(hold[9]&0x80);
373                 interlace=!!(hold[9]&0x40);
374                 //bool lcmsortflag=!!(hold[9]&0x20);
375                 lncols=lcmap ? (2<<(hold[9]&0x7)) : 0;
376                 if (lncols) {
377                     if (localcmap)
378                         delete [] localcmap;
379                     localcmap = new QRgb[lncols+1];
380                     localcmap[lncols] = Q_TRANSPARENT;
381                     ncols = lncols;
382                 } else {
383                     ncols = gncols;
384                 }
385                 frame++;
386                 if (frame == 0) {
387                     if (left || top || width<swidth || height<sheight) {
388                         // Not full-size image - erase with bg or transparent
389                         if (trans_index >= 0) {
390                             fillRect(image, 0, 0, swidth, sheight, color(trans_index));
391                             // ### Changed: QRect(0, 0, swidth, sheight)
392                         } else if (bgcol>=0) {
393                             fillRect(image, 0, 0, swidth, sheight, color(bgcol));
394                             // ### Changed: QRect(0, 0, swidth, sheight)
395                         }
396                     }
397                 }
398
399                 if (disposal == RestoreImage) {
400                     int l = qMin(swidth-1,left);
401                     int r = qMin(swidth-1,right);
402                     int t = qMin(sheight-1,top);
403                     int b = qMin(sheight-1,bottom);
404                     int w = r-l+1;
405                     int h = b-t+1;
406
407                     if (backingstore.width() < w
408                         || backingstore.height() < h) {
409                         // We just use the backing store as a byte array
410                         backingstore = QImage(qMax(backingstore.width(), w),
411                                               qMax(backingstore.height(), h),
412                                               QImage::Format_RGB32);
413                         memset(bits, 0, image->byteCount());
414                     }
415                     const int dest_bpl = backingstore.bytesPerLine();
416                     unsigned char *dest_data = backingstore.bits();
417                     for (int ln=0; ln<h; ln++) {
418                         memcpy(FAST_SCAN_LINE(dest_data, dest_bpl, ln),
419                                FAST_SCAN_LINE(bits, bpl, t+ln) + l, w*sizeof(QRgb));
420                     }
421                 }
422
423                 count=0;
424                 if (lcmap) {
425                     ccount=0;
426                     state=LocalColorMap;
427                 } else {
428                     state=TableImageLZWSize;
429                 }
430                 x = left;
431                 y = top;
432                 accum = 0;
433                 bitcount = 0;
434                 sp = stack;
435                 firstcode = oldcode = 0;
436                 needfirst = true;
437                 out_of_bounds = left>=swidth || y>=sheight;
438             }
439             break;
440           case TableImageLZWSize: {
441             lzwsize=ch;
442             if (lzwsize > max_lzw_bits) {
443                 state=Error;
444             } else {
445                 code_size=lzwsize+1;
446                 clear_code=1<<lzwsize;
447                 end_code=clear_code+1;
448                 max_code_size=2*clear_code;
449                 max_code=clear_code+2;
450                 int i;
451                 for (i=0; i<clear_code; i++) {
452                     table[0][i]=0;
453                     table[1][i]=i;
454                 }
455                 state=ImageDataBlockSize;
456             }
457             count=0;
458             break;
459           } case ImageDataBlockSize:
460             expectcount=ch;
461             if (expectcount) {
462                 state=ImageDataBlock;
463             } else {
464                 state=Introducer;
465                 digress = true;
466                 newFrame = true;
467             }
468             break;
469           case ImageDataBlock:
470             count++;
471             accum|=(ch<<bitcount);
472             bitcount+=8;
473             while (bitcount>=code_size && state==ImageDataBlock) {
474                 int code=accum&((1<<code_size)-1);
475                 bitcount-=code_size;
476                 accum>>=code_size;
477
478                 if (code==clear_code) {
479                     if (!needfirst) {
480                         code_size=lzwsize+1;
481                         max_code_size=2*clear_code;
482                         max_code=clear_code+2;
483                     }
484                     needfirst=true;
485                 } else if (code==end_code) {
486                     bitcount = -32768;
487                     // Left the block end arrive
488                 } else {
489                     if (needfirst) {
490                         firstcode=oldcode=code;
491                         if (!out_of_bounds && image->height() > y && firstcode!=trans_index)
492                             ((QRgb*)FAST_SCAN_LINE(bits, bpl, y))[x] = color(firstcode);
493                         x++;
494                         if (x>=swidth) out_of_bounds = true;
495                         needfirst=false;
496                         if (x>=left+width) {
497                             x=left;
498                             out_of_bounds = left>=swidth || y>=sheight;
499                             nextY(bits, bpl);
500                         }
501                     } else {
502                         incode=code;
503                         if (code>=max_code) {
504                             *sp++=firstcode;
505                             code=oldcode;
506                         }
507                         while (code>=clear_code+2) {
508                             if (code >= max_code) {
509                                 state = Error;
510                                 return -1;
511                             }
512                             *sp++=table[1][code];
513                             if (code==table[0][code]) {
514                                 state=Error;
515                                 return -1;
516                             }
517                             if (sp-stack>=(1<<(max_lzw_bits))*2) {
518                                 state=Error;
519                                 return -1;
520                             }
521                             code=table[0][code];
522                         }
523                         if (code < 0) {
524                             state = Error;
525                             return -1;
526                         }
527
528                         *sp++=firstcode=table[1][code];
529                         code=max_code;
530                         if (code<(1<<max_lzw_bits)) {
531                             table[0][code]=oldcode;
532                             table[1][code]=firstcode;
533                             max_code++;
534                             if ((max_code>=max_code_size)
535                              && (max_code_size<(1<<max_lzw_bits)))
536                             {
537                                 max_code_size*=2;
538                                 code_size++;
539                             }
540                         }
541                         oldcode=incode;
542                         const int h = image->height();
543                         const QRgb *map = lcmap ? localcmap : globalcmap;
544                         QRgb *line = 0;
545                         if (!out_of_bounds && h > y)
546                             line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
547                         while (sp>stack) {
548                             const uchar index = *(--sp);
549                             if (!out_of_bounds && h > y && index!=trans_index) {
550                                 if (index > ncols)
551                                     line[x] = Q_TRANSPARENT;
552                                 else
553                                     line[x] = map ? map[index] : 0;
554                             }
555                             x++;
556                             if (x>=swidth) out_of_bounds = true;
557                             if (x>=left+width) {
558                                 x=left;
559                                 out_of_bounds = left>=swidth || y>=sheight;
560                                 nextY(bits, bpl);
561                                 if (!out_of_bounds && h > y)
562                                     line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
563                             }
564                         }
565                     }
566                 }
567             }
568             partialNewFrame = true;
569             if (count==expectcount) {
570                 count=0;
571                 state=ImageDataBlockSize;
572             }
573             break;
574           case ExtensionLabel:
575             switch (ch) {
576             case 0xf9:
577                 state=GraphicControlExtension;
578                 break;
579             case 0xff:
580                 state=ApplicationExtension;
581                 break;
582 #if 0
583             case 0xfe:
584                 state=CommentExtension;
585                 break;
586             case 0x01:
587                 break;
588 #endif
589             default:
590                 state=SkipBlockSize;
591             }
592             count=0;
593             break;
594           case ApplicationExtension:
595             if (count<11) hold[count]=ch;
596             count++;
597             if (count==hold[0]+1) {
598                 if (qstrncmp((char*)(hold+1), "NETSCAPE", 8)==0) {
599                     // Looping extension
600                     state=NetscapeExtensionBlockSize;
601                 } else {
602                     state=SkipBlockSize;
603                 }
604                 count=0;
605             }
606             break;
607           case NetscapeExtensionBlockSize:
608             expectcount=ch;
609             count=0;
610             if (expectcount) state=NetscapeExtensionBlock;
611             else state=Introducer;
612             break;
613           case NetscapeExtensionBlock:
614             if (count<3) hold[count]=ch;
615             count++;
616             if (count==expectcount) {
617                 *loopCount = hold[1]+hold[2]*256;
618                 state=SkipBlockSize; // Ignore further blocks
619             }
620             break;
621           case GraphicControlExtension:
622             if (count<5) hold[count]=ch;
623             count++;
624             if (count==hold[0]+1) {
625                 disposePrevious(image);
626                 disposal=Disposal((hold[1]>>2)&0x7);
627                 //UNUSED: waitforuser=!!((hold[1]>>1)&0x1);
628                 int delay=count>3 ? LM(hold[2], hold[3]) : 1;
629                 // IE and mozilla use a minimum delay of 10. With the minimum delay of 10
630                 // we are compatible to them and avoid huge loads on the app and xserver.
631                 *nextFrameDelay = (delay < 2 ? 10 : delay) * 10;
632
633                 bool havetrans=hold[1]&0x1;
634                 trans_index = havetrans ? hold[4] : -1;
635
636                 count=0;
637                 state=SkipBlockSize;
638             }
639             break;
640           case SkipBlockSize:
641             expectcount=ch;
642             count=0;
643             if (expectcount) state=SkipBlock;
644             else state=Introducer;
645             break;
646           case SkipBlock:
647             count++;
648             if (count==expectcount) state=SkipBlockSize;
649             break;
650           case Done:
651             digress=true;
652             /* Netscape ignores the junk, so we do too.
653             length++; // Unget
654             state=Error; // More calls to this is an error
655             */
656             break;
657           case Error:
658             return -1; // Called again after done.
659         }
660     }
661     return initial-length;
662 }
663
664 /*!
665    Scans through the data stream defined by \a device and returns the image
666    sizes found in the stream in the \a imageSizes vector.
667 */
668 void QGIFFormat::scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount)
669 {
670     if (!device)
671         return;
672
673     qint64 oldPos = device->pos();
674     if (!device->seek(0))
675         return;
676
677     int colorCount = 0;
678     int localColorCount = 0;
679     int globalColorCount = 0;
680     int colorReadCount = 0;
681     bool localColormap = false;
682     bool globalColormap = false;
683     int count = 0;
684     int blockSize = 0;
685     int imageWidth = 0;
686     int imageHeight = 0;
687     bool done = false;
688     uchar hold[16];
689     State state = Header;
690
691     const int readBufferSize = 40960; // 40k read buffer
692     QByteArray readBuffer(device->read(readBufferSize));
693
694     if (readBuffer.isEmpty()) {
695         device->seek(oldPos);
696         return;
697     }
698
699     // This is a specialized version of the state machine from decode(),
700     // which doesn't do any image decoding or mallocing, and has an
701     // optimized way of skipping SkipBlocks, ImageDataBlocks and
702     // Global/LocalColorMaps.
703
704     while (!readBuffer.isEmpty()) {
705         int length = readBuffer.size();
706         const uchar *buffer = (const uchar *) readBuffer.constData();
707         while (!done && length) {
708             length--;
709             uchar ch = *buffer++;
710             switch (state) {
711             case Header:
712                 hold[count++] = ch;
713                 if (count == 6) {
714                     state = LogicalScreenDescriptor;
715                     count = 0;
716                 }
717                 break;
718             case LogicalScreenDescriptor:
719                 hold[count++] = ch;
720                 if (count == 7) {
721                     imageWidth = LM(hold[0], hold[1]);
722                     imageHeight = LM(hold[2], hold[3]);
723                     globalColormap = !!(hold[4] & 0x80);
724                     globalColorCount = 2 << (hold[4] & 0x7);
725                     count = 0;
726                     colorCount = globalColorCount;
727                     if (globalColormap) {
728                         int colorTableSize = 3 * globalColorCount;
729                         if (length >= colorTableSize) {
730                             // skip the global color table in one go
731                             length -= colorTableSize;
732                             buffer += colorTableSize;
733                             state = Introducer;
734                         } else {
735                             colorReadCount = 0;
736                             state = GlobalColorMap;
737                         }
738                     } else {
739                         state=Introducer;
740                     }
741                 }
742                 break;
743             case GlobalColorMap:
744             case LocalColorMap:
745                 hold[count++] = ch;
746                 if (count == 3) {
747                     if (++colorReadCount >= colorCount) {
748                         if (state == LocalColorMap)
749                             state = TableImageLZWSize;
750                         else
751                             state = Introducer;
752                     }
753                     count = 0;
754                 }
755                 break;
756             case Introducer:
757                 hold[count++] = ch;
758                 switch (ch) {
759                 case 0x2c:
760                     state = ImageDescriptor;
761                     break;
762                 case 0x21:
763                     state = ExtensionLabel;
764                     break;
765                 case 0x3b:
766                     state = Done;
767                     break;
768                 default:
769                     done = true;
770                     state = Error;
771                 }
772                 break;
773             case ImageDescriptor:
774                 hold[count++] = ch;
775                 if (count == 10) {
776                     int newLeft = LM(hold[1], hold[2]);
777                     int newTop = LM(hold[3], hold[4]);
778                     int newWidth = LM(hold[5], hold[6]);
779                     int newHeight = LM(hold[7], hold[8]);
780
781                     if (imageWidth/10 > qMax(newWidth,200))
782                         imageWidth = -1;
783                     if (imageHeight/10 > qMax(newHeight,200))
784                         imageHeight = -1;
785
786                     if (imageWidth <= 0)
787                         imageWidth = newLeft + newWidth;
788                     if (imageHeight <= 0)
789                         imageHeight = newTop + newHeight;
790
791                     *imageSizes << QSize(imageWidth, imageHeight);
792
793                     localColormap = !!(hold[9] & 0x80);
794                     localColorCount = localColormap ? (2 << (hold[9] & 0x7)) : 0;
795                     if (localColorCount)
796                         colorCount = localColorCount;
797                     else
798                         colorCount = globalColorCount;
799
800                     count = 0;
801                     if (localColormap) {
802                         int colorTableSize = 3 * localColorCount;
803                         if (length >= colorTableSize) {
804                             // skip the local color table in one go
805                             length -= colorTableSize;
806                             buffer += colorTableSize;
807                             state = TableImageLZWSize;
808                         } else {
809                             colorReadCount = 0;
810                             state = LocalColorMap;
811                         }
812                     } else {
813                         state = TableImageLZWSize;
814                     }
815                 }
816                 break;
817             case TableImageLZWSize:
818                 if (ch > max_lzw_bits)
819                     state = Error;
820                 else
821                     state = ImageDataBlockSize;
822                 count = 0;
823                 break;
824             case ImageDataBlockSize:
825                 blockSize = ch;
826                 if (blockSize) {
827                     if (length >= blockSize) {
828                         // we can skip the block in one go
829                         length -= blockSize;
830                         buffer += blockSize;
831                         count = 0;
832                     } else {
833                         state = ImageDataBlock;
834                     }
835                 } else {
836                     state = Introducer;
837                 }
838                 break;
839             case ImageDataBlock:
840                 ++count;
841                 if (count == blockSize) {
842                     count = 0;
843                     state = ImageDataBlockSize;
844                 }
845                 break;
846             case ExtensionLabel:
847                 switch (ch) {
848                 case 0xf9:
849                     state = GraphicControlExtension;
850                     break;
851                 case 0xff:
852                     state = ApplicationExtension;
853                     break;
854                 default:
855                     state = SkipBlockSize;
856                 }
857                 count = 0;
858                 break;
859             case ApplicationExtension:
860                 if (count < 11)
861                     hold[count] = ch;
862                 ++count;
863                 if (count == hold[0] + 1) {
864                     if (qstrncmp((char*)(hold+1), "NETSCAPE", 8) == 0)
865                         state=NetscapeExtensionBlockSize;
866                     else
867                         state=SkipBlockSize;
868                     count = 0;
869                 }
870                 break;
871             case GraphicControlExtension:
872                 if (count < 5)
873                     hold[count] = ch;
874                 ++count;
875                 if (count == hold[0] + 1) {
876                     count = 0;
877                     state = SkipBlockSize;
878                 }
879                 break;
880             case NetscapeExtensionBlockSize:
881                 blockSize = ch;
882                 count = 0;
883                 if (blockSize)
884                     state = NetscapeExtensionBlock;
885                 else
886                     state = Introducer;
887                 break;
888             case NetscapeExtensionBlock:
889                 if (count < 3)
890                     hold[count] = ch;
891                 count++;
892                 if (count == blockSize) {
893                     *loopCount = LM(hold[1], hold[2]);
894                     state = SkipBlockSize;
895                 }
896                 break;
897             case SkipBlockSize:
898                 blockSize = ch;
899                 count = 0;
900                 if (blockSize) {
901                     if (length >= blockSize) {
902                         // we can skip the block in one go
903                         length -= blockSize;
904                         buffer += blockSize;
905                     } else {
906                         state = SkipBlock;
907                     }
908                 } else {
909                     state = Introducer;
910                 }
911                 break;
912             case SkipBlock:
913                 ++count;
914                 if (count == blockSize)
915                     state = SkipBlockSize;
916                 break;
917             case Done:
918                 done = true;
919                 break;
920             case Error:
921                 device->seek(oldPos);
922                 return;
923             }
924         }
925         readBuffer = device->read(readBufferSize);
926     }
927     device->seek(oldPos);
928     return;
929 }
930
931 void QGIFFormat::fillRect(QImage *image, int col, int row, int w, int h, QRgb color)
932 {
933     if (w>0) {
934         for (int j=0; j<h; j++) {
935             QRgb *line = (QRgb*)image->scanLine(j+row);
936             for (int i=0; i<w; i++)
937                 *(line+col+i) = color;
938         }
939     }
940 }
941
942 void QGIFFormat::nextY(unsigned char *bits, int bpl)
943 {
944     int my;
945     switch (interlace) {
946     case 0: // Non-interlaced
947         // if (!out_of_bounds) {
948         //     ### Changed: QRect(left, y, right - left + 1, 1);
949         // }
950         y++;
951         break;
952     case 1: {
953         int i;
954         my = qMin(7, bottom-y);
955         // Don't dup with transparency
956         if (trans_index < 0) {
957             for (i=1; i<=my; i++) {
958                 memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
959                        (right-left+1)*sizeof(QRgb));
960             }
961         }
962
963         // if (!out_of_bounds) {
964         //     ### Changed: QRect(left, y, right - left + 1, my + 1);
965         // }
966 //        if (!out_of_bounds)
967 //            qDebug("consumer->changed(QRect(%d, %d, %d, %d))", left, y, right-left+1, my+1);
968         y+=8;
969         if (y>bottom) {
970             interlace++; y=top+4;
971             if (y > bottom) { // for really broken GIFs with bottom < 5
972                 interlace=2;
973                 y = top + 2;
974                 if (y > bottom) { // for really broken GIF with bottom < 3
975                     interlace = 0;
976                     y = top + 1;
977                 }
978             }
979         }
980     } break;
981     case 2: {
982         int i;
983         my = qMin(3, bottom-y);
984         // Don't dup with transparency
985         if (trans_index < 0) {
986             for (i=1; i<=my; i++) {
987                 memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
988                        (right-left+1)*sizeof(QRgb));
989             }
990         }
991
992         // if (!out_of_bounds) {
993         //     ### Changed: QRect(left, y, right - left + 1, my + 1);
994         // }
995         y+=8;
996         if (y>bottom) {
997             interlace++; y=top+2;
998             // handle broken GIF with bottom < 3
999             if (y > bottom) {
1000                 interlace = 3;
1001                 y = top + 1;
1002             }
1003         }
1004     } break;
1005     case 3: {
1006         int i;
1007         my = qMin(1, bottom-y);
1008         // Don't dup with transparency
1009         if (trans_index < 0) {
1010             for (i=1; i<=my; i++) {
1011                 memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
1012                        (right-left+1)*sizeof(QRgb));
1013             }
1014         }
1015         // if (!out_of_bounds) {
1016         //     ### Changed: QRect(left, y, right - left + 1, my + 1);
1017         // }
1018         y+=4;
1019         if (y>bottom) { interlace++; y=top+1; }
1020     } break;
1021     case 4:
1022         // if (!out_of_bounds) {
1023         //     ### Changed: QRect(left, y, right - left + 1, 1);
1024         // }
1025         y+=2;
1026     }
1027
1028     // Consume bogus extra lines
1029     if (y >= sheight) out_of_bounds=true; //y=bottom;
1030 }
1031
1032 inline QRgb QGIFFormat::color(uchar index) const
1033 {
1034     if (index == trans_index || index > ncols)
1035         return Q_TRANSPARENT;
1036
1037     QRgb *map = lcmap ? localcmap : globalcmap;
1038     return map ? map[index] : 0;
1039 }
1040
1041 //-------------------------------------------------------------------------
1042 //-------------------------------------------------------------------------
1043 //-------------------------------------------------------------------------
1044
1045 QGifHandler::QGifHandler()
1046 {
1047     gifFormat = new QGIFFormat;
1048     nextDelay = 100;
1049     loopCnt = -1;
1050     frameNumber = -1;
1051     scanIsCached = false;
1052 }
1053
1054 QGifHandler::~QGifHandler()
1055 {
1056     delete gifFormat;
1057 }
1058
1059 // Does partial decode if necessary, just to see if an image is coming
1060
1061 bool QGifHandler::imageIsComing() const
1062 {
1063     const int GifChunkSize = 4096;
1064
1065     while (!gifFormat->partialNewFrame) {
1066         if (buffer.isEmpty()) {
1067             buffer += device()->read(GifChunkSize);
1068             if (buffer.isEmpty())
1069                 break;
1070         }
1071
1072         int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
1073                                         &nextDelay, &loopCnt);
1074         if (decoded == -1)
1075             break;
1076         buffer.remove(0, decoded);
1077     }
1078     return gifFormat->partialNewFrame;
1079 }
1080
1081 bool QGifHandler::canRead() const
1082 {
1083     if (canRead(device()) || imageIsComing()) {
1084         setFormat("gif");
1085         return true;
1086     }
1087
1088     return false;
1089 }
1090
1091 bool QGifHandler::canRead(QIODevice *device)
1092 {
1093     if (!device) {
1094         qWarning("QGifHandler::canRead() called with no device");
1095         return false;
1096     }
1097
1098     char head[6];
1099     if (device->peek(head, sizeof(head)) == sizeof(head))
1100         return qstrncmp(head, "GIF87a", 6) == 0
1101             || qstrncmp(head, "GIF89a", 6) == 0;
1102     return false;
1103 }
1104
1105 bool QGifHandler::read(QImage *image)
1106 {
1107     const int GifChunkSize = 4096;
1108
1109     while (!gifFormat->newFrame) {
1110         if (buffer.isEmpty()) {
1111             buffer += device()->read(GifChunkSize);
1112             if (buffer.isEmpty())
1113                 break;
1114         }
1115
1116         int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
1117                                         &nextDelay, &loopCnt);
1118         if (decoded == -1)
1119             break;
1120         buffer.remove(0, decoded);
1121     }
1122     if (gifFormat->newFrame || (gifFormat->partialNewFrame && device()->atEnd())) {
1123         *image = lastImage;
1124         ++frameNumber;
1125         gifFormat->newFrame = false;
1126         gifFormat->partialNewFrame = false;
1127         return true;
1128     }
1129
1130     return false;
1131 }
1132
1133 bool QGifHandler::write(const QImage &image)
1134 {
1135     Q_UNUSED(image);
1136     return false;
1137 }
1138
1139 bool QGifHandler::supportsOption(ImageOption option) const
1140 {
1141     if (!device() || device()->isSequential())
1142         return option == Animation;
1143     else
1144         return option == Size
1145             || option == Animation;
1146 }
1147
1148 QVariant QGifHandler::option(ImageOption option) const
1149 {
1150     if (option == Size) {
1151         if (!scanIsCached) {
1152             QGIFFormat::scan(device(), &imageSizes, &loopCnt);
1153             scanIsCached = true;
1154         }
1155         // before the first frame is read, or we have an empty data stream
1156         if (frameNumber == -1)
1157             return (imageSizes.count() > 0) ? QVariant(imageSizes.at(0)) : QVariant();
1158         // after the last frame has been read, the next size is undefined
1159         if (frameNumber >= imageSizes.count() - 1)
1160             return QVariant();
1161         // and the last case: the size of the next frame
1162         return imageSizes.at(frameNumber + 1);
1163     } else if (option == Animation) {
1164         return true;
1165     }
1166     return QVariant();
1167 }
1168
1169 void QGifHandler::setOption(ImageOption option, const QVariant &value)
1170 {
1171     Q_UNUSED(option);
1172     Q_UNUSED(value);
1173 }
1174
1175 int QGifHandler::nextImageDelay() const
1176 {
1177     return nextDelay;
1178 }
1179
1180 int QGifHandler::imageCount() const
1181 {
1182     if (!scanIsCached) {
1183         QGIFFormat::scan(device(), &imageSizes, &loopCnt);
1184         scanIsCached = true;
1185     }
1186     return imageSizes.count();
1187 }
1188
1189 int QGifHandler::loopCount() const
1190 {
1191     if (!scanIsCached) {
1192         QGIFFormat::scan(device(), &imageSizes, &loopCnt);
1193         scanIsCached = true;
1194     }
1195
1196     if (loopCnt == 0)
1197         return -1;
1198     else if (loopCnt == -1)
1199         return 0;
1200     else
1201         return loopCnt;
1202 }
1203
1204 int QGifHandler::currentImageNumber() const
1205 {
1206     return frameNumber;
1207 }
1208
1209 QByteArray QGifHandler::name() const
1210 {
1211     return "gif";
1212 }
1213
1214 QT_END_NAMESPACE