File indexing completed on 2024-04-21 14:57:44

0001 /*
0002     This file is part of the KDE libraries
0003 
0004     Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
0005     Copyright (C) 2001-2003 Dirk Mueller <mueller@kde.org>
0006     Copyright (C) 2003 Apple Computer, Inc
0007 
0008     This library is free software; you can redistribute it and/or
0009     modify it under the terms of the GNU Library General Public
0010     License as published by the Free Software Foundation; either
0011     version 2 of the License, or (at your option) any later version.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Library General Public License for more details.
0017 
0018     You should have received a copy of the GNU Library General Public License
0019     along with this library; see the file COPYING.LIB.  If not, write to
0020     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0021     Boston, MA 02110-1301, USA.
0022 
0023     This class provides all functionality needed for loading images, style sheets and html
0024     pages from the web. It has a memory cache for these objects.
0025 */
0026 #ifndef _khtml_loader_h
0027 #define _khtml_loader_h
0028 
0029 #include "loader_client.h"
0030 
0031 #include <stdlib.h>
0032 #include <QObject>
0033 #include <QPixmap>
0034 #include <QBuffer>
0035 #include <QStringList>
0036 #include <QTextCodec>
0037 #include <QTimer>
0038 #include <QSet>
0039 #include <QDateTime>
0040 #include <QLinkedList>
0041 #include <QUrl>
0042 
0043 #include <kio/global.h>
0044 
0045 #include <khtml_settings.h>
0046 #include <dom/dom_string.h>
0047 #include "imload/image.h"
0048 #include "imload/imageowner.h"
0049 
0050 class KHTMLPart;
0051 
0052 class KJob;
0053 namespace KIO
0054 {
0055 class Job;
0056 }
0057 
0058 namespace DOM
0059 {
0060 class DocumentImpl;
0061 }
0062 
0063 namespace khtml
0064 {
0065 class CachedObject;
0066 class Request;
0067 class DocLoader;
0068 
0069 /**
0070  * @internal
0071  *
0072  * A cached object. Classes who want to use this object should derive
0073  * from CachedObjectClient, to get the function calls in case the requested data has arrived.
0074  *
0075  * This class also does the actual communication with kio and loads the file.
0076  */
0077 class CachedObject
0078 {
0079 public:
0080     enum Type {
0081         Image,
0082         CSSStyleSheet,
0083         Script,
0084         Sound,
0085         Font
0086     };
0087 
0088     enum Status {
0089         Unknown,      // let imagecache decide what to do with it
0090         New,          // inserting new image
0091         Pending,      // only partially loaded
0092         Persistent,   // never delete this pixmap
0093         Cached        // regular case
0094     };
0095 
0096     enum PreloadResult {
0097         PreloadNotReferenced = 0,
0098         PreloadReferenced,
0099         PreloadReferencedWhileLoading,
0100         PreloadReferencedWhileComplete
0101     };
0102 
0103     PreloadResult preloadResult() const
0104     {
0105         return m_preloadResult;
0106     }
0107     void setProspectiveRequest()
0108     {
0109         m_prospectiveRequest = true;
0110     }
0111 
0112     CachedObject(const DOM::DOMString &url, Type type, KIO::CacheControl _cachePolicy, int size)
0113         : m_url(url), m_type(type), m_cachePolicy(_cachePolicy),
0114           m_size(size)
0115     {
0116         m_status = Pending;
0117         m_accessCount = 0;
0118         m_cachePolicy = _cachePolicy;
0119         m_request = nullptr;
0120         m_deleted = false;
0121         m_free = false;
0122         m_hadError = false;
0123         m_wasBlocked = false;
0124         m_prev = m_next = nullptr;
0125         m_preloadCount = 0;
0126         m_preloadResult = PreloadNotReferenced;
0127         m_prospectiveRequest = false;
0128     }
0129     virtual ~CachedObject();
0130 
0131     virtual void data(QBuffer &buffer, bool eof) = 0;
0132     virtual void error(int err, const char *text) = 0;
0133 
0134     const DOM::DOMString &url() const
0135     {
0136         return m_url;
0137     }
0138     Type type() const
0139     {
0140         return m_type;
0141     }
0142 
0143     virtual void ref(CachedObjectClient *consumer);
0144     virtual void deref(CachedObjectClient *consumer);
0145 
0146     int count() const
0147     {
0148         return m_clients.count();
0149     }
0150     int accessCount() const
0151     {
0152         return m_accessCount;
0153     }
0154 
0155     bool isPreloaded() const
0156     {
0157         return m_preloadCount;
0158     }
0159     void increasePreloadCount()
0160     {
0161         ++m_preloadCount;
0162     }
0163     void decreasePreloadCount()
0164     {
0165         assert(m_preloadCount);
0166         --m_preloadCount;
0167     }
0168 
0169     void setStatus(Status s)
0170     {
0171         m_status = s;
0172     }
0173     Status status() const
0174     {
0175         return m_status;
0176     }
0177 
0178     virtual void setCharset(const QString & /*charset*/) {}
0179 
0180     QTextCodec *codecForBuffer(const QString &charset, const QByteArray &buffer) const;
0181 
0182     int size() const
0183     {
0184         return m_size;
0185     }
0186 
0187     bool isLoaded() const
0188     {
0189         return !m_loading;
0190     }
0191     bool hadError() const
0192     {
0193         return m_hadError;
0194     }
0195 
0196     bool free() const
0197     {
0198         return m_free;
0199     }
0200 
0201     KIO::CacheControl cachePolicy() const
0202     {
0203         return m_cachePolicy;
0204     }
0205 
0206     void setRequest(Request *_request);
0207 
0208     bool canDelete() const
0209     {
0210         return (m_clients.count() == 0 && !m_request && !m_preloadCount);
0211     }
0212 
0213     void setExpireDate(const QDateTime &_expireDate)
0214     {
0215         m_expireDate = _expireDate;
0216     }
0217 
0218     bool isExpired() const;
0219 
0220     virtual void finish();
0221 
0222     /**
0223      * List of acceptable mimetypes separated by ",". A mimetype may contain a wildcard.
0224      */
0225     // e.g. "text/*"
0226     QString accept() const
0227     {
0228         return m_accept;
0229     }
0230     void setAccept(const QString &_accept)
0231     {
0232         m_accept = _accept;
0233     }
0234 
0235     // the mimetype that was eventually used
0236     QString mimetype() const
0237     {
0238         return m_mimetype;
0239     }
0240 
0241 protected:
0242     void setSize(int size);
0243     QHash<CachedObjectClient *, CachedObjectClient *> m_clients;
0244     DOM::DOMString m_url;
0245     QString m_accept;
0246     QString m_mimetype;
0247     Request *m_request;
0248     Type m_type;
0249     Status m_status;
0250     int m_accessCount;
0251     KIO::CacheControl m_cachePolicy;
0252     QDateTime m_expireDate;
0253     int m_size;
0254     unsigned m_preloadCount;
0255     PreloadResult m_preloadResult: 3;
0256     bool m_deleted : 1;
0257     bool m_loading : 1;
0258     bool m_free : 1;
0259     bool m_hadError : 1;
0260     bool m_wasBlocked : 1;
0261     bool m_prospectiveRequest: 1;
0262 
0263 private:
0264     bool allowInLRUList() const
0265     {
0266         return canDelete() && !m_free && status() != Persistent;
0267     }
0268     CachedObject *m_next;
0269     CachedObject *m_prev;
0270     friend class Cache;
0271     friend class ::KHTMLPart;
0272     friend class Loader;
0273 };
0274 
0275 bool isAcceptableCSSMimetype(const DOM::DOMString &mimetype);
0276 
0277 /**
0278  * a cached style sheet. also used for loading xml documents.
0279  *
0280  * ### rename to CachedTextDoc or something since it's more generic than just for css
0281  */
0282 class CachedCSSStyleSheet : public CachedObject
0283 {
0284 public:
0285     CachedCSSStyleSheet(DocLoader *dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy,
0286                         const char *accept);
0287     CachedCSSStyleSheet(const DOM::DOMString &url, const QString &stylesheet_data);
0288 
0289     const DOM::DOMString &sheet() const
0290     {
0291         return m_sheet;
0292     }
0293 
0294     void ref(CachedObjectClient *consumer) override;
0295 
0296     void data(QBuffer &buffer, bool eof) override;
0297     void error(int err, const char *text) override;
0298 
0299     void setCharsetHint(const QString &charset)
0300     {
0301         m_charsetHint = charset;
0302     }
0303     void setCharset(const QString &charset) override
0304     {
0305         m_charset = charset;
0306     }
0307     QString checkCharset(const QByteArray &buffer) const;
0308 
0309 protected:
0310     void checkNotify();
0311 
0312     DOM::DOMString m_sheet;
0313     QString m_charset;
0314     QString m_charsetHint;
0315     int m_err;
0316     QString m_errText;
0317 };
0318 
0319 /**
0320  * a cached script
0321  */
0322 class CachedScript : public CachedObject
0323 {
0324 public:
0325     CachedScript(DocLoader *dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, const char *accept);
0326     CachedScript(const DOM::DOMString &url, const QString &script_data);
0327 
0328     const DOM::DOMString &script() const
0329     {
0330         return m_script;
0331     }
0332 
0333     void ref(CachedObjectClient *consumer) override;
0334 
0335     void data(QBuffer &buffer, bool eof) override;
0336     void error(int err, const char *text) override;
0337 
0338     void checkNotify();
0339 
0340     bool isLoaded() const
0341     {
0342         return !m_loading;
0343     }
0344     void setCharset(const QString &charset) override
0345     {
0346         m_charset = charset;
0347     }
0348 
0349 protected:
0350     QString m_charset;
0351     DOM::DOMString m_script;
0352 };
0353 
0354 class ImageSource;
0355 
0356 /**
0357  * a cached image
0358  */
0359 class CachedImage : public QObject, public CachedObject, public khtmlImLoad::ImageOwner
0360 {
0361     Q_OBJECT
0362 public:
0363     CachedImage(DocLoader *dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, const char *accept);
0364     virtual ~CachedImage();
0365 
0366     QPixmap pixmap() const;
0367     QPixmap *scaled_pixmap(int xWidth, int xHeight);
0368     QPixmap  tiled_pixmap(const QColor &bg, int xWidth = -1, int xHeight = -1);
0369 
0370     QSize pixmap_size() const;    // returns the size of the complete (i.e. when finished) loading
0371     //QRect valid_rect() const;     // returns the rectangle of pixmap that has been loaded already
0372 
0373     bool canRender() const
0374     {
0375         return !isErrorImage() && pixmap_size().width() > 0 && pixmap_size().height() > 0;
0376     }
0377     void ref(CachedObjectClient *consumer) override;
0378     void deref(CachedObjectClient *consumer) override;
0379 
0380     void data(QBuffer &buffer, bool eof) override;
0381     void error(int err, const char *text) override;
0382 
0383     bool isComplete() const
0384     {
0385         return i && i->complete();
0386     }
0387     bool isTransparent() const
0388     {
0389         return false;
0390     } //### isFullyTransparent; }
0391     bool isErrorImage() const
0392     {
0393         return m_hadError;
0394     }
0395     bool isBlockedImage() const
0396     {
0397         return m_wasBlocked;
0398     }
0399     const QString &suggestedFilename() const
0400     {
0401         return m_suggestedFilename;
0402     }
0403     void setSuggestedFilename(const QString &s)
0404     {
0405         m_suggestedFilename = s;
0406     }
0407 #ifdef IMAGE_TITLES
0408     const QString &suggestedTitle() const
0409     {
0410         return m_suggestedTitle;
0411     }
0412     void setSuggestedTitle(const QString &s)
0413     {
0414         m_suggestedTitle = s;
0415     }
0416 #else
0417     const QString &suggestedTitle() const
0418     {
0419         return m_suggestedFilename;
0420     }
0421 #endif
0422 
0423     void setShowAnimations(KHTMLSettings::KAnimationAdvice);
0424 
0425     void finish() override;
0426 
0427     khtmlImLoad::Image *image()
0428     {
0429         return i;
0430     }
0431 
0432 protected:
0433     void clear();
0434 
0435 private:
0436     /**
0437      Interface to the image
0438     */
0439     void imageHasGeometry(khtmlImLoad::Image *img, int width, int height) override;
0440     void imageChange(khtmlImLoad::Image *img, QRect region) override;
0441     void imageError(khtmlImLoad::Image *img) override;
0442     void imageDone(khtmlImLoad::Image *img) override;
0443 private:
0444     void doNotifyFinished();
0445 
0446     void do_notify(const QRect &r);
0447     khtmlImLoad::Image *i;
0448 
0449     QString m_suggestedFilename;
0450 #ifdef IMAGE_TITLES
0451     QString m_suggestedTitle;
0452 #endif
0453     QPixmap *bg;
0454     QPixmap *scaled;
0455     QRgb bgColor;
0456     QSize bgSize;
0457 
0458     friend class Cache;
0459     friend class ::KHTMLPart;
0460 };
0461 
0462 /**
0463  * a cached sound
0464  */
0465 class CachedSound : public CachedObject
0466 {
0467 public:
0468     CachedSound(DocLoader *dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, const char *accept);
0469 
0470     QByteArray sound() const
0471     {
0472         return m_sound;
0473     }
0474 
0475     void ref(CachedObjectClient *consumer) override;
0476     void data(QBuffer &buffer, bool eof) override;
0477     void error(int err, const char *text) override;
0478 
0479     void checkNotify();
0480 
0481     bool isLoaded() const
0482     {
0483         return !m_loading;
0484     }
0485 
0486 protected:
0487     QByteArray m_sound;
0488 };
0489 
0490 /**
0491  * a cached font
0492  */
0493 class CachedFont : public CachedObject
0494 {
0495 public:
0496     CachedFont(DocLoader *dl, const DOM::DOMString &url, KIO::CacheControl cachePolicy, const char *accept);
0497 
0498     QByteArray font() const
0499     {
0500         return m_font;
0501     }
0502 
0503     void ref(CachedObjectClient *consumer) override;
0504     void data(QBuffer &buffer, bool eof) override;
0505     void error(int err, const char *text) override;
0506 
0507     void checkNotify();
0508 
0509     bool isLoaded() const
0510     {
0511         return !m_loading;
0512     }
0513 
0514 protected:
0515     QByteArray m_font;
0516 };
0517 
0518 /**
0519  * @internal
0520  *
0521  * Manages the loading of scripts/images/stylesheets for a particular document
0522  */
0523 class DocLoader
0524 {
0525 public:
0526     DocLoader(KHTMLPart *, DOM::DocumentImpl *);
0527     ~DocLoader();
0528 
0529     CachedImage *requestImage(const DOM::DOMString &url);
0530     CachedCSSStyleSheet *requestStyleSheet(const DOM::DOMString &url, const QString &charsetHint,
0531                                            const char *accept = "text/css", bool userSheet = false);
0532     CachedScript *requestScript(const DOM::DOMString &url, const QString &charset);
0533     CachedSound *requestSound(const DOM::DOMString &url);
0534     CachedFont *requestFont(const DOM::DOMString &url);
0535     bool willLoadMediaElement(const DOM::DOMString &url);
0536 
0537     bool autoloadImages() const
0538     {
0539         return m_bautoloadImages;
0540     }
0541     KIO::CacheControl cachePolicy() const
0542     {
0543         return m_cachePolicy;
0544     }
0545     KHTMLSettings::KAnimationAdvice showAnimations() const
0546     {
0547         return m_showAnimations;
0548     }
0549     QDateTime expireDate() const
0550     {
0551         return m_expireDate;
0552     }
0553     KHTMLPart *part() const
0554     {
0555         return m_part;
0556     }
0557     DOM::DocumentImpl *doc() const
0558     {
0559         return m_doc;
0560     }
0561 
0562     void setCacheCreationDate(const QDateTime &);
0563     void setExpireDate(const QDateTime &);
0564     void setRelativeExpireDate(qint64 seconds);
0565     void setAutoloadImages(bool);
0566     void setCachePolicy(KIO::CacheControl cachePolicy)
0567     {
0568         m_cachePolicy = cachePolicy;
0569     }
0570     void setShowAnimations(KHTMLSettings::KAnimationAdvice);
0571     void insertCachedObject(CachedObject *o) const;
0572     void removeCachedObject(CachedObject *o) const
0573     {
0574         m_docObjects.remove(o);
0575     }
0576     void clearPreloads();
0577     void registerPreload(CachedObject *);
0578     void printPreloadStats();
0579 
0580 private:
0581     bool needReload(CachedObject *existing, const QString &fullUrl);
0582 
0583     friend class Cache;
0584     friend class DOM::DocumentImpl;
0585     friend class ::KHTMLPart;
0586 
0587     QStringList m_reloadedURLs;
0588     mutable QSet<CachedObject *> m_docObjects;
0589     QSet<CachedObject *> m_preloads;
0590     QDateTime m_expireDate;
0591     QDateTime m_creationDate;
0592     KIO::CacheControl m_cachePolicy;
0593     bool m_bautoloadImages : 1;
0594     KHTMLSettings::KAnimationAdvice m_showAnimations : 2;
0595     KHTMLPart *m_part;
0596     DOM::DocumentImpl *m_doc;
0597 };
0598 
0599 /**
0600  * @internal
0601  */
0602 class Request
0603 {
0604 public:
0605     Request(DocLoader *dl, CachedObject *_object, bool _incremental, int priority);
0606     ~Request();
0607     bool incremental;
0608     int priority; // -10 to 10, smaller values mean higher priority
0609     QBuffer m_buffer;
0610     CachedObject *object;
0611     DocLoader *m_docLoader;
0612 };
0613 
0614 /**
0615  * @internal
0616  */
0617 class Loader : public QObject
0618 {
0619 
0620     Q_OBJECT
0621 
0622 public:
0623     Loader();
0624     ~Loader();
0625 
0626     void load(DocLoader *dl, CachedObject *object, bool incremental = true, int priority = 0);
0627 
0628     int numRequests(DocLoader *dl) const;
0629     void cancelRequests(DocLoader *dl);
0630 
0631     // may return 0L
0632     KIO::Job *jobForRequest(const DOM::DOMString &url) const;
0633 
0634 Q_SIGNALS:
0635     void requestStarted(khtml::DocLoader *dl, khtml::CachedObject *obj);
0636     void requestDone(khtml::DocLoader *dl, khtml::CachedObject *obj);
0637     void requestFailed(khtml::DocLoader *dl, khtml::CachedObject *obj);
0638 
0639 protected Q_SLOTS:
0640     void slotFinished(KJob *);
0641     void slotMimetype(KIO::Job *, const QString &s);
0642     void slotData(KIO::Job *, const QByteArray &);
0643 
0644 protected:
0645     void scheduleRequest(Request *req);
0646     QHash<KIO::Job *, Request *> m_requestsLoading;
0647     QStringList m_supportedImageTypes;
0648 };
0649 
0650 /**
0651 * @internal
0652 *
0653 * Provides a cache/loader for objects needed for displaying the html page.
0654 * At the moment these are stylesheets, scripts and images
0655 */
0656 class Cache
0657 {
0658     friend class DocLoader;
0659 
0660     template<typename CachedObjectType, enum CachedObject::Type CachedType>
0661     static CachedObjectType *requestObject(DocLoader *dl, const QUrl &kurl, const char *accept);
0662 
0663 public:
0664     /**
0665      * init the cache in case it's not already. This needs to get called once
0666      * before using it.
0667      */
0668     KHTML_EXPORT static void init();
0669 
0670     /**
0671      * Ask the cache for some url. Will return a cachedObject, and
0672      * load the requested data in case it's not cached
0673          * if the DocLoader is zero, the url must be full-qualified.
0674          * Otherwise, it is automatically base-url expanded
0675      */
0676 //  static CachedImage *requestImage(const QUrl& url)
0677 //         { return Cache::requestObject<CachedImage, CachedObject::Image>( 0, url, 0 ); }
0678 
0679     /**
0680      * Pre-loads a stylesheet into the cache.
0681      */
0682     static void preloadStyleSheet(const QString &url, const QString &stylesheet_data);
0683 
0684     /**
0685      * Pre-loads a script into the cache.
0686      */
0687     static void preloadScript(const QString &url, const QString &script_data);
0688 
0689     static void setSize(int bytes);
0690     static int size()
0691     {
0692         return maxSize;
0693     }
0694     static void statistics();
0695     KHTML_EXPORT static void flush(bool force = false);
0696 
0697     /**
0698      * clears the cache
0699      * Warning: call this only at the end of your program, to clean
0700      * up memory (useful for finding memory holes)
0701      */
0702     KHTML_EXPORT static void clear();
0703 
0704     static Loader *loader()
0705     {
0706         return m_loader;
0707     }
0708 
0709     static QPixmap *nullPixmap;
0710     static QPixmap *brokenPixmap;
0711     static QPixmap *blockedPixmap;
0712     static int cacheSize;
0713 
0714     static void removeCacheEntry(CachedObject *object);
0715 
0716 private:
0717 
0718     static void checkLRUAndUncacheableListIntegrity();
0719 
0720     friend class CachedObject;
0721 
0722     static QHash<QString, CachedObject *> *cache;
0723     static QLinkedList<DocLoader *> *docloader;
0724     static QLinkedList<CachedObject *> *freeList;
0725     static void insertInLRUList(CachedObject *);
0726     static void removeFromLRUList(CachedObject *);
0727 
0728     static int totalSizeOfLRU;
0729     static int maxSize;
0730 
0731     static Loader *m_loader;
0732 };
0733 
0734 } // namespace
0735 
0736 #endif