WebCore:
[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     /**
309      * a cached image
310      */
311     class CachedImage : public QObject, public CachedObject
312     {
313         Q_OBJECT
314     public:
315         CachedImage(DocLoader* dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, time_t _expireDate);
316         virtual ~CachedImage();
317
318         const QPixmap &pixmap() const;
319         const QPixmap &tiled_pixmap(const QColor& bg);
320
321         QSize pixmap_size() const;    // returns the size of the complete (i.e. when finished) loading
322         QRect valid_rect() const;     // returns the rectangle of pixmap that has been loaded already
323
324         void ref(CachedObjectClient *consumer);
325         virtual void deref(CachedObjectClient *consumer);
326
327         virtual void data( QBuffer &buffer, bool eof );
328         virtual void error( int err, const char *text );
329
330         bool isTransparent() const { return isFullyTransparent; }
331         bool isErrorImage() const { return errorOccured; }
332
333         void setShowAnimations( KHTMLSettings::KAnimationAdvice );
334
335         virtual bool schedule() const { return true; }
336
337         void checkNotify();
338
339     protected:
340         void clear();
341
342     private slots:
343         /**
344          * gets called, whenever a QMovie changes frame
345          */
346         void movieUpdated( const QRect &rect );
347         void movieStatus(int);
348         void movieResize(const QSize&);
349         void deleteMovie();
350
351     private:
352         void do_notify(const QPixmap& p, const QRect& r);
353
354         QMovie* m;
355         QPixmap* p;
356         QPixmap* bg;
357         QRgb bgColor;
358         mutable QPixmap* pixPart;
359
360         ImageSource* imgSource;
361         const char* formatType;  // Is the name of the movie format type
362
363         int width;
364         int height;
365
366         // Is set if movie format type ( incremental/animation) was checked
367         bool typeChecked : 1;
368         bool isFullyTransparent : 1;
369         bool errorOccured : 1;
370         bool monochrome : 1;
371         KHTMLSettings::KAnimationAdvice m_showAnimations : 2;
372
373         friend class Cache;
374
375 #if APPLE_CHANGES
376     public:
377         int dataSize() const { return m_dataSize; }
378     private:
379         int m_dataSize;
380 #endif
381     };
382
383 #ifdef KHTML_XSLT
384     class CachedXSLStyleSheet : public CachedObject
385     {
386 public:
387         CachedXSLStyleSheet(DocLoader* dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, time_t _expireDate);
388
389         const DOM::DOMString& sheet() const { return m_sheet; }
390         
391         virtual void ref(CachedObjectClient *consumer);
392         virtual void deref(CachedObjectClient *consumer);
393         
394         virtual void data(QBuffer &buffer, bool eof);
395         virtual void error(int err, const char *text);
396         
397         virtual bool schedule() const { return true; }
398         
399         void checkNotify();
400         
401 protected:
402         DOM::DOMString m_sheet;
403         QTextCodec* m_codec;
404     };
405 #endif
406     
407 #ifndef KHTML_NO_XBL
408     class CachedXBLDocument : public CachedObject
409     {
410     public:
411         CachedXBLDocument(DocLoader* dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, time_t _expireDate);
412         virtual ~CachedXBLDocument();
413         
414         XBL::XBLDocumentImpl* document() const { return m_document; }
415         
416         virtual void ref(CachedObjectClient *consumer);
417         virtual void deref(CachedObjectClient *consumer);
418         
419         virtual void data( QBuffer &buffer, bool eof );
420         virtual void error( int err, const char *text );
421         
422         virtual bool schedule() const { return true; }
423         
424         void checkNotify();
425         
426 protected:
427         XBL::XBLDocumentImpl* m_document;
428         QTextCodec* m_codec;
429     };
430 #endif
431
432     /**
433      * @internal
434      *
435      * Manages the loading of scripts/images/stylesheets for a particular document
436      */
437     class DocLoader
438     {
439     public:
440         DocLoader(KHTMLPart*, DOM::DocumentImpl*);
441         ~DocLoader();
442
443         CachedImage *requestImage( const DOM::DOMString &url);
444         CachedCSSStyleSheet *requestStyleSheet( const DOM::DOMString &url, const QString& charset);
445         CachedScript *requestScript( const DOM::DOMString &url, const QString& charset);
446
447 #ifdef KHTML_XSLT
448         CachedXSLStyleSheet* requestXSLStyleSheet(const DOM::DOMString& url);
449 #endif
450 #ifndef KHTML_NO_XBL
451         CachedXBLDocument* requestXBLDocument(const DOM::DOMString &url);
452 #endif
453
454         bool autoloadImages() const { return m_bautoloadImages; }
455         KIO::CacheControl cachePolicy() const { return m_cachePolicy; }
456         KHTMLSettings::KAnimationAdvice showAnimations() const { return m_showAnimations; }
457         time_t expireDate() const { return m_expireDate; }
458         KHTMLPart* part() const { return m_part; }
459         DOM::DocumentImpl* doc() const { return m_doc; }
460
461         void setExpireDate( time_t );
462         void setAutoloadImages( bool );
463         void setCachePolicy( KIO::CacheControl cachePolicy );
464         void setShowAnimations( KHTMLSettings::KAnimationAdvice );
465         void removeCachedObject( CachedObject*) const;
466
467     private:
468         bool needReload(const KURL &fullUrl);
469
470         friend class Cache;
471         friend class DOM::DocumentImpl;
472
473         QStringList m_reloadedURLs;
474         mutable QPtrList<CachedObject> m_docObjects;
475         time_t m_expireDate;
476         KIO::CacheControl m_cachePolicy;
477         bool m_bautoloadImages : 1;
478         KHTMLSettings::KAnimationAdvice m_showAnimations : 2;
479         KHTMLPart* m_part;
480         DOM::DocumentImpl* m_doc;
481     };
482
483     /**
484      * @internal
485      */
486     class Request
487     {
488     public:
489         Request(DocLoader* dl, CachedObject *_object, bool _incremental);
490         ~Request();
491         bool incremental;
492         QBuffer m_buffer;
493         CachedObject *object;
494         DocLoader* m_docLoader;
495      };
496
497     /**
498      * @internal
499      */
500     class Loader : public QObject
501     {
502         Q_OBJECT
503
504     public:
505         Loader();
506         ~Loader();
507
508         void load(DocLoader* dl, CachedObject *object, bool incremental = true);
509
510         int numRequests( DocLoader* dl ) const;
511         void cancelRequests( DocLoader* dl );
512
513         // may return 0L
514         KIO::Job *jobForRequest( const DOM::DOMString &url ) const;
515
516 #if APPLE_CHANGES
517         KWQLoader *kwq;
518 #endif
519
520     signals:
521         void requestStarted( khtml::DocLoader* dl, khtml::CachedObject* obj );
522         void requestDone( khtml::DocLoader* dl, khtml::CachedObject *obj );
523         void requestFailed( khtml::DocLoader* dl, khtml::CachedObject *obj );
524
525     protected slots:
526         void slotFinished( KIO::Job * );
527 #if APPLE_CHANGES
528         void slotData( KIO::Job *, const char *data, int size );
529         void slotReceivedResponse ( KIO::Job *, NSURLResponse *response );
530         void slotAllData( KIO::Job *, NSData *data );
531 #else
532         void slotData( KIO::Job *, const QByteArray & );
533 #endif
534
535     private:
536         void servePendingRequests();
537
538         QPtrList<Request> m_requestsPending;
539         QPtrDict<Request> m_requestsLoading;
540 #ifdef HAVE_LIBJPEG
541         KJPEGFormatType m_jpegloader;
542 #endif
543     };
544
545         /**
546      * @internal
547      *
548      * Provides a cache/loader for objects needed for displaying the html page.
549      * At the moment these are stylesheets, scripts and images
550      */
551     class Cache
552     {
553         friend class DocLoader;
554     public:
555         /**
556          * init the cache in case it's not already. This needs to get called once
557          * before using it.
558          */
559         static void init();
560         
561         /**
562          * Ask the cache for some url. Will return a cachedObject, and
563          * load the requested data in case it's not cahced
564          * if the DocLoader is zero, the url must be full-qualified.
565          * Otherwise, it is automatically base-url expanded
566          */
567         static CachedImage *requestImage( DocLoader* l, const DOM::DOMString &url, bool reload=false, time_t _expireDate=0);
568         static CachedImage *requestImage( DocLoader* l, const KURL &url, bool reload=false, time_t _expireDate=0);
569
570         /**
571          * Ask the cache for some url. Will return a cachedObject, and
572          * load the requested data in case it's not cached
573          */
574         static CachedCSSStyleSheet *requestStyleSheet( DocLoader* l, const DOM::DOMString &url, bool reload=false, time_t _expireDate=0, const QString& charset = QString::null);
575
576 #ifdef KHTML_XSLT
577         // Ask the cache for an XSL stylesheet.
578         static CachedXSLStyleSheet* requestXSLStyleSheet(DocLoader* l, const DOM::DOMString &url, 
579                                                          bool reload=false, time_t _expireDate=0);
580 #endif
581 #ifndef KHTML_NO_XBL
582         // Ask the cache for an XBL document.
583         static CachedXBLDocument* requestXBLDocument(DocLoader* l, const DOM::DOMString &url, 
584                                                      bool reload=false, time_t _expireDate=0);
585 #endif
586
587         /**
588          * Pre-loads a stylesheet into the cache.
589          */
590         static void preloadStyleSheet(const QString &url, const QString &stylesheet_data);
591
592         /**
593          * Ask the cache for some url. Will return a cachedObject, and
594          * load the requested data in case it's not cahced
595          */
596         static CachedScript *requestScript( DocLoader* l, const DOM::DOMString &url, bool reload=false, time_t _expireDate=0, const QString& charset=QString::null);
597
598         /**
599          * Pre-loads a script into the cache.
600          */
601         static void preloadScript(const QString &url, const QString &script_data);
602
603         /**
604          * sets the size of the cache. This will only hod approximately, since the size some
605          * cached objects (like stylesheets) take up in memory is not exaclty known.
606          */
607         static void setSize( int bytes );
608         /**
609          * returns the size of the cache
610          */
611         static int size() { return maxSize; };
612
613         static int maxCacheableObjectSize() { return maxCacheable; }
614
615         /**
616          * prints some statistics to stdout
617          */
618         static void statistics();
619
620         /**
621          * clean up cache
622          */
623         static void flush(bool force=false);
624
625         /**
626          * clears the cache
627          * Warning: call this only at the end of your program, to clean
628          * up memory (useful for finding memory holes)
629          */
630         static void clear();
631
632         static Loader *loader() { return m_loader; }
633
634         static QPixmap *nullPixmap;
635         static QPixmap *brokenPixmap;
636
637         static void removeCacheEntry( CachedObject *object );
638
639 #if APPLE_CHANGES
640         struct TypeStatistic {
641             int count;
642             int size;
643             TypeStatistic() : count(0), size(0) { }
644         };
645         
646         struct Statistics {
647             TypeStatistic images;
648             TypeStatistic movies;
649             TypeStatistic styleSheets;
650             TypeStatistic scripts;
651 #ifdef KHTML_XSLT
652             TypeStatistic xslStyleSheets;
653 #endif
654 #ifndef KHTML_NO_XBL
655             TypeStatistic xblDocs;
656 #endif
657             TypeStatistic other;
658         };
659
660         static Statistics getStatistics();
661         static void flushAll();
662         static void setCacheDisabled(bool);
663 #endif
664
665         static void insertInLRUList(CachedObject *);
666         static void removeFromLRUList(CachedObject *);
667         static bool adjustSize(CachedObject *, int sizeDelta);
668         
669         static LRUList* getLRUListFor(CachedObject* o);
670         
671         static void checkLRUAndUncacheableListIntegrity();
672
673     protected:
674         static QDict<CachedObject> *cache;
675         static QPtrList<DocLoader>* docloader;
676     
677         static int maxSize;
678         static int maxCacheable;
679         static int flushCount;
680     
681         static Loader *m_loader;
682     
683         static unsigned long s_ulRefCnt;
684     
685         static void moveToHeadOfLRUList(CachedObject *);
686     
687         static LRUList *m_LRULists;
688         static int m_totalSizeOfLRULists;
689             
690         static CachedObject *m_headOfUncacheableList;
691             
692         static int m_countOfLRUAndUncacheableLists;
693     };
694
695 };
696
697 #endif