Reviewed by Darin.
[WebKit-https.git] / WebCore / khtml / misc / loader.h
1 /*
2     This file is part of the KDE libraries
3
4     Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
5     Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
6     Copyright (C) 2004 Apple Computer, Inc.
7
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Library General Public
10     License as published by the Free Software Foundation; either
11     version 2 of the License, or (at your option) any later version.
12
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Library General Public License for more details.
17
18     You should have received a copy of the GNU Library General Public License
19     along with this library; see the file COPYING.LIB.  If not, write to
20     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21     Boston, MA 02111-1307, USA.
22
23     This class provides all functionality needed for loading images, style sheets and html
24     pages from the web. It has a memory cache for these objects.
25 */
26 #ifndef _khtml_loader_h
27 #define _khtml_loader_h
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include <time.h>
34
35 #include "loader_client.h"
36 #ifdef HAVE_LIBJPEG
37 #include "loader_jpeg.h"
38 #endif
39
40 #include <stdlib.h>
41 #include <qptrlist.h>
42 #include <qobject.h>
43 #include <qptrdict.h>
44 #include <qdict.h>
45 #include <qpixmap.h>
46 #include <qbuffer.h>
47 #include <qstringlist.h>
48 #include <qtextcodec.h>
49
50 #include <kurl.h>
51 #include <kio/global.h>
52
53 #include <khtml_settings.h>
54 #include <dom/dom_string.h>
55
56 class QMovie;
57 class KHTMLPart;
58
59 namespace KIO {
60   class Job;
61   class TransferJob;
62 }
63
64 namespace DOM
65 {
66     class CSSStyleSheetImpl;
67     class DocumentImpl;
68 };
69
70 #if APPLE_CHANGES
71
72 class KWQLoader;
73
74 #if __OBJC__
75 @class NSData;
76 @class NSURLResponse;
77 #else
78 class NSData;
79 class NSURLResponse;
80 #endif
81
82 #endif
83
84 namespace khtml
85 {
86     class CachedObject;
87     class Request;
88     class DocLoader;
89
90  #define MAX_LRU_LISTS 20
91     
92     struct LRUList {
93         CachedObject* m_head;
94         CachedObject* m_tail;
95     
96         LRUList();
97         ~LRUList();
98     };
99     
100     /**
101      * @internal
102      *
103      * A cached object. Classes who want to use this object should derive
104      * from CachedObjectClient, to get the function calls in case the requested data has arrived.
105      *
106      * This class also does the actual communication with kio and loads the file.
107      */
108     class CachedObject
109     {
110     public:
111         enum Type {
112             Image,
113             CSSStyleSheet,
114             Script
115 #ifdef KHTML_XSLT
116             , XSLStyleSheet
117 #endif
118 #ifndef KHTML_NO_XBL
119             , XBL
120 #endif
121         };
122
123         enum Status {
124             NotCached,    // this URL is not cached
125             Unknown,      // let imagecache decide what to do with it
126             New,          // inserting new image
127         Pending,      // only partially loaded
128             Persistent,   // never delete this pixmap
129             Cached,       // regular case
130             Uncacheable   // too big to be cached,
131         };                // will be destroyed as soon as possible
132
133         CachedObject(const DOM::DOMString &url, Type type, KIO::CacheControl _cachePolicy, time_t _expireDate, int size = 0)
134         {
135             m_url = url;
136             m_type = type;
137             m_status = Pending;
138             m_size = size;
139             m_free = false;
140             m_cachePolicy = _cachePolicy;
141             m_request = 0;
142 #if APPLE_CHANGES
143         m_response = 0;
144         m_allData = 0;
145 #endif            
146             m_expireDate = _expireDate;
147         m_deleted = false;
148         m_expireDateChanged = false;
149         
150         m_accessCount = 0;
151         
152         m_nextInLRUList = 0;
153         m_prevInLRUList = 0;
154         }
155         virtual ~CachedObject();
156
157         virtual void data( QBuffer &buffer, bool eof) = 0;
158         virtual void error( int err, const char *text ) = 0;
159
160         const DOM::DOMString &url() const { return m_url; }
161         Type type() const { return m_type; }
162
163         virtual void ref(CachedObjectClient *consumer);
164         virtual void deref(CachedObjectClient *consumer);
165
166         int count() const { return m_clients.count(); }
167
168         Status status() const { return m_status; }
169
170         int size() const { return m_size; }
171
172     int accessCount() const { return m_accessCount; }
173     void increaseAccessCount() { m_accessCount++; }
174     
175         /**
176          * computes the status of an object after loading.
177          * the result depends on the objects size and the size of the cache
178          * also updates the expire date on the cache entry file
179          */
180         void finish();
181
182         /**
183          * Called by the cache if the object has been removed from the cache dict
184          * while still being referenced. This means the object should kill itself
185          * if its reference counter drops down to zero.
186          */
187         void setFree( bool b ) { m_free = b; }
188
189         KIO::CacheControl cachePolicy() const { return m_cachePolicy; }
190
191         void setRequest(Request *_request);
192
193 #if APPLE_CHANGES
194         NSURLResponse *response() const { return m_response; }
195         void setResponse(NSURLResponse *response);
196         NSData *allData() const { return m_allData; }
197         void setAllData (NSData *data);
198 #endif
199
200         bool canDelete() const { return (m_clients.count() == 0 && !m_request); }
201
202         void setExpireDate(time_t _expireDate, bool changeHttpCache);
203         
204         bool isExpired() const;
205
206         virtual bool schedule() const { return false; }
207
208         /**
209          * List of acceptable mimetypes seperated by ",". A mimetype may contain a wildcard.
210          */
211         // e.g. "text/*"
212         QString accept() const { return m_accept; }
213         void setAccept(const QString &_accept) { m_accept = _accept; }
214
215     protected:
216         void setSize(int size);
217         
218         QPtrDict<CachedObjectClient> m_clients;
219
220         DOM::DOMString m_url;
221         QString m_accept;
222         Request *m_request;
223 #if APPLE_CHANGES
224         NSURLResponse *m_response;
225         NSData *m_allData;
226 #endif
227         Type m_type;
228         Status m_status;
229     private:
230         int m_size;
231     int m_accessCount;
232     
233     protected:
234         time_t m_expireDate;
235         KIO::CacheControl m_cachePolicy;
236         bool m_free : 1;
237         bool m_deleted : 1;
238         bool m_loading : 1;
239         bool m_expireDateChanged : 1;
240     
241     private:
242         bool allowInLRUList() { return canDelete() && status() != Persistent; }
243         
244         CachedObject *m_nextInLRUList;
245         CachedObject *m_prevInLRUList;
246         friend class Cache;
247     };
248
249
250     /**
251      * a cached style sheet
252      */
253     class CachedCSSStyleSheet : public CachedObject
254     {
255     public:
256         CachedCSSStyleSheet(DocLoader* dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, time_t _expireDate, const QString& charset);
257         CachedCSSStyleSheet(const DOM::DOMString &url, const QString &stylesheet_data);
258         virtual ~CachedCSSStyleSheet();
259
260         const DOM::DOMString &sheet() const { return m_sheet; }
261
262         virtual void ref(CachedObjectClient *consumer);
263         virtual void deref(CachedObjectClient *consumer);
264
265         virtual void data( QBuffer &buffer, bool eof );
266         virtual void error( int err, const char *text );
267
268         virtual bool schedule() const { return true; }
269
270         void checkNotify();
271
272     protected:
273         DOM::DOMString m_sheet;
274         QTextCodec* m_codec;
275     };
276
277     /**
278      * a cached script
279      */
280     class CachedScript : public CachedObject
281     {
282     public:
283         CachedScript(DocLoader* dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, time_t _expireDate, const QString& charset);
284         CachedScript(const DOM::DOMString &url, const QString &script_data);
285         virtual ~CachedScript();
286
287         const DOM::DOMString &script() const { return m_script; }
288
289         virtual void ref(CachedObjectClient *consumer);
290         virtual void deref(CachedObjectClient *consumer);
291
292         virtual void data( QBuffer &buffer, bool eof );
293         virtual void error( int err, const char *text );
294
295         virtual bool schedule() const { return false; }
296
297         void checkNotify();
298
299         bool isLoaded() const { return !m_loading; }
300
301     protected:
302         DOM::DOMString m_script;
303         QTextCodec* m_codec;
304     };
305
306     class ImageSource;
307
308 #if APPLE_CHANGES    
309     class CachedImage;
310     
311     class CachedImageCallback
312     {
313     public:
314         CachedImageCallback (CachedImage *c) : cachedImage(c), refCount(1), headerReceived(false) {};
315
316         void ref() { refCount++; }
317         void deref() { if (--refCount == 0) delete this; }
318         
319         void notifyUpdate();
320         void notifyFinished();
321         void notifyDecodingError();
322         void clear();
323         void handleError();
324         
325     private:
326         CachedImage *cachedImage;
327         uint refCount;
328         bool headerReceived;
329     };
330 #endif
331         
332     /**
333      * a cached image
334      */
335     class CachedImage : public QObject, public CachedObject
336     {
337         Q_OBJECT
338     public:
339         CachedImage(DocLoader* dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, time_t _expireDate);
340         virtual ~CachedImage();
341
342         const QPixmap &pixmap() const;
343         const QPixmap &tiled_pixmap(const QColor& bg);
344
345         QSize pixmap_size() const;    // returns the size of the complete (i.e. when finished) loading
346         QRect valid_rect() const;     // returns the rectangle of pixmap that has been loaded already
347
348         void ref(CachedObjectClient *consumer);
349         virtual void deref(CachedObjectClient *consumer);
350
351         virtual void data( QBuffer &buffer, bool eof );
352         virtual void error( int err, const char *text );
353
354         bool isTransparent() const { return isFullyTransparent; }
355         bool isErrorImage() const { return errorOccured; }
356
357         void setShowAnimations( KHTMLSettings::KAnimationAdvice );
358
359         virtual bool schedule() const { return true; }
360
361         void checkNotify();
362
363     protected:
364         void clear();
365
366     private slots:
367         /**
368          * gets called, whenever a QMovie changes frame
369          */
370         void movieUpdated( const QRect &rect );
371         void movieStatus(int);
372         void movieResize(const QSize&);
373         void deleteMovie();
374
375     private:
376         void do_notify(const QPixmap& p, const QRect& r);
377
378         QMovie* m;
379         QPixmap* p;
380         QPixmap* bg;
381         QRgb bgColor;
382         mutable QPixmap* pixPart;
383
384         ImageSource* imgSource;
385         const char* formatType;  // Is the name of the movie format type
386
387         int width;
388         int height;
389
390         // Is set if movie format type ( incremental/animation) was checked
391         bool typeChecked : 1;
392         bool isFullyTransparent : 1;
393         bool errorOccured : 1;
394         bool monochrome : 1;
395         KHTMLSettings::KAnimationAdvice m_showAnimations : 2;
396
397         friend class Cache;
398
399 #if APPLE_CHANGES
400     public:
401         int dataSize() const { return m_dataSize; }
402         CachedImageCallback *decoderCallback() const { return m_decoderCallback; }
403     private:
404         friend class CachedImageCallback;
405         
406         int m_dataSize;
407         CachedImageCallback *m_decoderCallback;
408 #endif
409     };
410
411 #ifdef KHTML_XSLT
412     class CachedXSLStyleSheet : public CachedObject
413     {
414 public:
415         CachedXSLStyleSheet(DocLoader* dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, time_t _expireDate);
416
417         const DOM::DOMString& sheet() const { return m_sheet; }
418         
419         virtual void ref(CachedObjectClient *consumer);
420         virtual void deref(CachedObjectClient *consumer);
421         
422         virtual void data(QBuffer &buffer, bool eof);
423         virtual void error(int err, const char *text);
424         
425         virtual bool schedule() const { return true; }
426         
427         void checkNotify();
428         
429 protected:
430         DOM::DOMString m_sheet;
431         QTextCodec* m_codec;
432     };
433 #endif
434     
435 #ifndef KHTML_NO_XBL
436     class CachedXBLDocument : public CachedObject
437     {
438     public:
439         CachedXBLDocument(DocLoader* dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, time_t _expireDate);
440         virtual ~CachedXBLDocument();
441         
442         XBL::XBLDocumentImpl* document() const { return m_document; }
443         
444         virtual void ref(CachedObjectClient *consumer);
445         virtual void deref(CachedObjectClient *consumer);
446         
447         virtual void data( QBuffer &buffer, bool eof );
448         virtual void error( int err, const char *text );
449         
450         virtual bool schedule() const { return true; }
451         
452         void checkNotify();
453         
454 protected:
455         XBL::XBLDocumentImpl* m_document;
456         QTextCodec* m_codec;
457     };
458 #endif
459
460     /**
461      * @internal
462      *
463      * Manages the loading of scripts/images/stylesheets for a particular document
464      */
465     class DocLoader
466     {
467     public:
468         DocLoader(KHTMLPart*, DOM::DocumentImpl*);
469         ~DocLoader();
470
471         CachedImage *requestImage( const DOM::DOMString &url);
472         CachedCSSStyleSheet *requestStyleSheet( const DOM::DOMString &url, const QString& charset);
473         CachedScript *requestScript( const DOM::DOMString &url, const QString& charset);
474
475 #ifdef KHTML_XSLT
476         CachedXSLStyleSheet* requestXSLStyleSheet(const DOM::DOMString& url);
477 #endif
478 #ifndef KHTML_NO_XBL
479         CachedXBLDocument* requestXBLDocument(const DOM::DOMString &url);
480 #endif
481
482         bool autoloadImages() const { return m_bautoloadImages; }
483         KIO::CacheControl cachePolicy() const { return m_cachePolicy; }
484         KHTMLSettings::KAnimationAdvice showAnimations() const { return m_showAnimations; }
485         time_t expireDate() const { return m_expireDate; }
486         KHTMLPart* part() const { return m_part; }
487         DOM::DocumentImpl* doc() const { return m_doc; }
488
489         void setExpireDate( time_t );
490         void setAutoloadImages( bool );
491         void setCachePolicy( KIO::CacheControl cachePolicy );
492         void setShowAnimations( KHTMLSettings::KAnimationAdvice );
493         void removeCachedObject( CachedObject*) const;
494                 
495         void setLoadInProgress(bool);
496         bool loadInProgress() const { return m_loadInProgress; }
497
498     private:
499         bool needReload(const KURL &fullUrl);
500
501         friend class Cache;
502         friend class DOM::DocumentImpl;
503
504         QStringList m_reloadedURLs;
505         mutable QPtrList<CachedObject> m_docObjects;
506         time_t m_expireDate;
507         KIO::CacheControl m_cachePolicy;
508         bool m_bautoloadImages : 1;
509         KHTMLSettings::KAnimationAdvice m_showAnimations : 2;
510         KHTMLPart* m_part;
511         DOM::DocumentImpl* m_doc;
512         bool m_loadInProgress;
513     };
514
515     /**
516      * @internal
517      */
518     class Request
519     {
520     public:
521         Request(DocLoader* dl, CachedObject *_object, bool _incremental);
522         ~Request();
523         bool incremental;
524         QBuffer m_buffer;
525         CachedObject *object;
526         DocLoader* m_docLoader;
527      };
528
529     /**
530      * @internal
531      */
532     class Loader : public QObject
533     {
534         Q_OBJECT
535
536     public:     
537         Loader();
538         ~Loader();
539
540         void load(DocLoader* dl, CachedObject *object, bool incremental = true);
541
542         int numRequests( DocLoader* dl ) const;
543         void cancelRequests( DocLoader* dl );
544
545 #if APPLE_CHANGES
546         void removeBackgroundDecodingRequest (Request *r);
547 #endif
548         
549         // may return 0L
550         KIO::Job *jobForRequest( const DOM::DOMString &url ) const;
551
552 #if APPLE_CHANGES
553         KWQLoader *kwq;
554 #endif
555
556     signals:
557         friend class CachedImageCallback;
558
559         void requestStarted( khtml::DocLoader* dl, khtml::CachedObject* obj );
560         void requestDone( khtml::DocLoader* dl, khtml::CachedObject *obj );
561         void requestFailed( khtml::DocLoader* dl, khtml::CachedObject *obj );
562
563     protected slots:
564 #if APPLE_CHANGES
565         void slotFinished( KIO::Job * , NSData *allData);
566         void slotData( KIO::Job *, const char *data, int size );
567         void slotReceivedResponse ( KIO::Job *, NSURLResponse *response );
568 #else
569         void slotFinished( KIO::Job * );
570         void slotData( KIO::Job *, const QByteArray & );
571 #endif
572
573     private:
574         void servePendingRequests();
575
576 #if APPLE_CHANGES
577         virtual bool isKHTMLLoader() const;
578 #endif
579
580         QPtrList<Request> m_requestsPending;
581         QPtrDict<Request> m_requestsLoading;
582
583 #if APPLE_CHANGES
584         QPtrList<Request> m_requestsBackgroundDecoding;
585 #endif
586
587 #ifdef HAVE_LIBJPEG
588         KJPEGFormatType m_jpegloader;
589 #endif
590     };
591
592         /**
593      * @internal
594      *
595      * Provides a cache/loader for objects needed for displaying the html page.
596      * At the moment these are stylesheets, scripts and images
597      */
598     class Cache
599     {
600         friend class DocLoader;
601     public:
602         /**
603          * init the cache in case it's not already. This needs to get called once
604          * before using it.
605          */
606         static void init();
607         
608         /**
609          * Ask the cache for some url. Will return a cachedObject, and
610          * load the requested data in case it's not cahced
611          * if the DocLoader is zero, the url must be full-qualified.
612          * Otherwise, it is automatically base-url expanded
613          */
614         static CachedImage *requestImage( DocLoader* l, const DOM::DOMString &url, bool reload=false, time_t _expireDate=0);
615         static CachedImage *requestImage( DocLoader* l, const KURL &url, bool reload=false, time_t _expireDate=0);
616
617         /**
618          * Ask the cache for some url. Will return a cachedObject, and
619          * load the requested data in case it's not cached
620          */
621         static CachedCSSStyleSheet *requestStyleSheet( DocLoader* l, const DOM::DOMString &url, bool reload=false, time_t _expireDate=0, const QString& charset = QString::null);
622
623 #ifdef KHTML_XSLT
624         // Ask the cache for an XSL stylesheet.
625         static CachedXSLStyleSheet* requestXSLStyleSheet(DocLoader* l, const DOM::DOMString &url, 
626                                                          bool reload=false, time_t _expireDate=0);
627 #endif
628 #ifndef KHTML_NO_XBL
629         // Ask the cache for an XBL document.
630         static CachedXBLDocument* requestXBLDocument(DocLoader* l, const DOM::DOMString &url, 
631                                                      bool reload=false, time_t _expireDate=0);
632 #endif
633
634         /**
635          * Pre-loads a stylesheet into the cache.
636          */
637         static void preloadStyleSheet(const QString &url, const QString &stylesheet_data);
638
639         /**
640          * Ask the cache for some url. Will return a cachedObject, and
641          * load the requested data in case it's not cahced
642          */
643         static CachedScript *requestScript( DocLoader* l, const DOM::DOMString &url, bool reload=false, time_t _expireDate=0, const QString& charset=QString::null);
644
645         /**
646          * Pre-loads a script into the cache.
647          */
648         static void preloadScript(const QString &url, const QString &script_data);
649
650         /**
651          * sets the size of the cache. This will only hod approximately, since the size some
652          * cached objects (like stylesheets) take up in memory is not exaclty known.
653          */
654         static void setSize( int bytes );
655         /**
656          * returns the size of the cache
657          */
658         static int size() { return maxSize; };
659
660         static int maxCacheableObjectSize() { return maxCacheable; }
661
662         /**
663          * prints some statistics to stdout
664          */
665         static void statistics();
666
667         /**
668          * clean up cache
669          */
670         static void flush(bool force=false);
671
672         /**
673          * clears the cache
674          * Warning: call this only at the end of your program, to clean
675          * up memory (useful for finding memory holes)
676          */
677         static void clear();
678
679         static Loader *loader() { return m_loader; }
680
681         static QPixmap *nullPixmap;
682         static QPixmap *brokenPixmap;
683
684         static void removeCacheEntry( CachedObject *object );
685
686 #if APPLE_CHANGES
687         struct TypeStatistic {
688             int count;
689             int size;
690             TypeStatistic() : count(0), size(0) { }
691         };
692         
693         struct Statistics {
694             TypeStatistic images;
695             TypeStatistic movies;
696             TypeStatistic styleSheets;
697             TypeStatistic scripts;
698 #ifdef KHTML_XSLT
699             TypeStatistic xslStyleSheets;
700 #endif
701 #ifndef KHTML_NO_XBL
702             TypeStatistic xblDocs;
703 #endif
704             TypeStatistic other;
705         };
706
707         static Statistics getStatistics();
708         static void flushAll();
709         static void setCacheDisabled(bool);
710 #endif
711
712         static void insertInLRUList(CachedObject *);
713         static void removeFromLRUList(CachedObject *);
714         static bool adjustSize(CachedObject *, int sizeDelta);
715         
716         static LRUList* getLRUListFor(CachedObject* o);
717         
718         static void checkLRUAndUncacheableListIntegrity();
719
720     protected:
721         static QDict<CachedObject> *cache;
722         static QPtrList<DocLoader>* docloader;
723     
724         static int maxSize;
725         static int maxCacheable;
726         static int flushCount;
727     
728         static Loader *m_loader;
729     
730         static unsigned long s_ulRefCnt;
731     
732         static void moveToHeadOfLRUList(CachedObject *);
733     
734         static LRUList *m_LRULists;
735         static int m_totalSizeOfLRULists;
736             
737         static CachedObject *m_headOfUncacheableList;
738             
739         static int m_countOfLRUAndUncacheableLists;
740     };
741
742 };
743
744 #endif