File indexing completed on 2024-05-19 05:01:20

0001 /*
0002     This file is part of the KDE project.
0003 
0004     SPDX-FileCopyrightText: 2008 Dirk Mueller <mueller@kde.org>
0005     SPDX-FileCopyrightText: 2008 Urs Wolfer <uwolfer @ kde.org>
0006     SPDX-FileCopyrightText: 2009 Dawit Alemayehu <adawit@kde.org>
0007 
0008     SPDX-License-Identifier: LGPL-2.1-or-later
0009 */
0010 
0011 #ifndef WEBENGINEPAGE_H
0012 #define WEBENGINEPAGE_H
0013 
0014 #include "websslinfo.h"
0015 #include "kwebenginepartlib_export.h"
0016 #include "qtwebengine6compat.h"
0017 #include "browserextension.h"
0018 #include "webenginepartdownloadmanager.h"
0019 
0020 #include <QWebEnginePage>
0021 
0022 #include <QUrl>
0023 #include <QMultiHash>
0024 #include <QPointer>
0025 #include <QScopedPointer>
0026 #include <QWebEngineFullScreenRequest>
0027 
0028 class QAuthenticator;
0029 class WebSslInfo;
0030 class WebEnginePart;
0031 class KPasswdServerClient;
0032 class WebEngineWallet;
0033 class WebEngineDownloadJob;
0034 
0035 class WebEnginePage : public QWebEnginePage
0036 {
0037     Q_OBJECT
0038 public:
0039     explicit WebEnginePage(WebEnginePart *wpart, QWidget *parent = nullptr);
0040     ~WebEnginePage() override;
0041 
0042     /**
0043      * Returns the SSL information for the current page.
0044      *
0045      * @see WebSslInfo.
0046      */
0047     const WebSslInfo& sslInfo() const;
0048 
0049     /**
0050      * Sets the page's SSL information to @p other.
0051      *
0052      * @see WebSslInfo
0053      */
0054     void setSslInfo (const WebSslInfo &other);
0055 
0056     void requestDownload(QWebEngineDownloadRequest *item, bool newWindow, WebEnginePartDownloadManager::DownloadObjective objective);
0057 
0058     void setStatusBarText(const QString &text);
0059 
0060     /**
0061      * @brief Sets the webengine part to be used by this object.
0062      * @param part the part
0063      */
0064     void setPart(WebEnginePart *part);
0065 
0066 #ifndef REMOTE_DND_NOT_HANDLED_BY_WEBENGINE
0067     /**
0068      * @brief Informs the page that a drop operation has been started
0069      *
0070      * Calling this method changes the behavior of createWindow()
0071      * @note Since `QWebEngineView` doesn't provide a way to tell when a drop operation actually end,
0072      * there's no function to inform that the drop operation has ended. The page considers the
0073      * drop operation to have ended when one the following happens:
0074      * - createWindow() is called
0075      * - the `loadStarted` signal is emitted
0076      * - 100ms have elapsed since the last call to this method (this time interval has been chosen arbitrary: it should
0077      *   be enough for the drop operation to have actually ended but short enough to make it unlikely that
0078      *   the user has started another action)
0079      * @see m_dropOperationTimer
0080      * @see createWindow()
0081      * @see WebEngineView::dropEvent
0082      */
0083     void setDropOperationStarted();
0084 #endif
0085 
0086 #if QT_VERSION_MAJOR == 6
0087     QWidget* view() const;
0088 #endif
0089 
0090 Q_SIGNALS:
0091     /**
0092      * This signal is emitted whenever a user cancels/aborts a load resource
0093      * request.
0094      */
0095     void loadAborted(const QUrl &url);
0096 
0097     void mainFrameNavigationRequested(WebEnginePage *page, const QUrl);
0098 
0099 protected:
0100     /**
0101      * Returns the webengine part in use by this object.
0102      * @internal
0103      */
0104     WebEnginePart* part() const;
0105 
0106     /**
0107      * @brief Override of `QWebEnginePage::createWindow`
0108      *
0109      * Reimplemented for internal reasons, the API is not affected.
0110      *
0111      * By default, a new NewWindowPage will be returned; however, calling setDropOperationStarted changes
0112      * this behavior: in this case, no pages will be created and the function returns `this`. The default
0113      * behavior is restored when the drop operation ends (see setDropOperationStarted()).
0114      * @param type the window type to create. This is ignored if setDropOperationStarted has been called with `true`
0115      * @return a new NewWindowPage or `this` if within a drop operation
0116      * @see setDropOperationStarted
0117      */
0118     QWebEnginePage* createWindow(WebWindowType type) override;
0119 protected:
0120 
0121     /**
0122      * Reimplemented for internal reasons, the API is not affected.
0123      * @internal
0124      */
0125     bool acceptNavigationRequest(const QUrl& request, NavigationType type, bool isMainFrame) override;
0126 
0127 #if QT_VERSION_MAJOR < 6
0128     /**
0129     * @brief Override of `QWebEnginePage::certificateError`
0130     *
0131     * If the error is overridable, it first checks whether the user has already choosen to permanently ignore the error, in which case it returns `true`.
0132     * If the user hasn't made such a choice, the error is deferred and a WebEnginePartCertificateErrorDlg is shown. The result is handled by handleCertificateError.
0133     *
0134     * @internal
0135     * A problem arises if the certificate error happens while loading a page opened from a part which is not a WebEnginePart (this also includes the case when the
0136     * URL is entered in the location bar when the part is active). In this case, the URL is first loaded by KIO, then by WebEnginePart. If there's a certificate error,
0137     * it will be reported twice: by KIO and by the WebEnginePart. The old trick of using `m_urlLoadedByPart` doesn't work anymore, because if the current part is
0138     * a WebEnginePart, WebEnginePart::openUrl will be called, but everything will be handled by WebEnginePart.
0139     *
0140     * @param _ce the certificate error
0141     * @return @b false if the error is not overridable and @true in all other cases. Note that if @b _ce is deferred, according to the documentation for `QWebEngineCertificateError
0142     * the return value is ignored.
0143     */
0144     bool certificateError(const QWebEngineCertificateError &_ce) override;
0145 #else
0146 signals:
0147 protected Q_SLOTS:
0148     void handleCertificateError(const QWebEngineCertificateError &ce);
0149 #endif
0150 
0151 protected Q_SLOTS:
0152     void slotLoadFinished(bool ok);
0153     virtual void slotGeometryChangeRequested(const QRect& rect);
0154     void slotFeaturePermissionRequested(const QUrl& url, QWebEnginePage::Feature feature);
0155     void slotAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth);
0156     void changeFullScreenMode(QWebEngineFullScreenRequest req);
0157     void changeLifecycleState(QWebEnginePage::LifecycleState recommendedState);
0158 
0159     /**
0160      * @brief Updates the stylesheet applied to the page
0161      *
0162      * Since `QtWebEngine` doesn't directly support custom stylesheets, this is done using javascript
0163      * @param script the script to run to update the stylesheet
0164      * @see WebEnginePartControls::updateUserStyleSheet
0165      * @see WebEnginePartControls::updateStyleSheet
0166      */
0167     void updateUserStyleSheet(const QString &script);
0168 
0169 private:
0170     bool checkFormData(const QUrl& url) const;
0171     bool handleMailToUrl (const QUrl& , NavigationType type) const;
0172     void setPageJScriptPolicy(const QUrl& url);
0173     bool askBrowserToOpenUrl(const QUrl &url, const QString &mimetype=QString(), const KParts::OpenUrlArguments &args = KParts::OpenUrlArguments(), const BrowserArguments &bargs = BrowserArguments());
0174     bool downloadWithExternalDonwloadManager(const QUrl &url);
0175 
0176     /**
0177      * @brief Whether WebEnginePart should open an URL by itself or delegate the main application
0178      *
0179      * This tries to take into account the user preferences and it's needed, for example, to ensure that
0180      * the link "Home Folder" in the introduction page is displayed in the part the user choose for directories
0181      * rather than in WebEnginePart.
0182      *
0183      * This function is meant to be used by acceptNavigationRequest(), which unfortunately means it doesn't know
0184      * the URL mimetype. Because of this, only preferences related to the URL's scheme can be applied. In particular:
0185      * - if the URL has the `file` scheme, its mimetype is detected using QMimeTypeDatabase and the appropriate
0186      *  preferences are enforced
0187      * - if the URL has the `trash` or `remote` schemes, it is handled by the application
0188      * @param url the URL to open
0189      * @return `true` if WebEnginePart should open the URL and `false` if it should let the application open it
0190      */
0191     bool shouldOpenUrl(const QUrl &url) const;
0192 
0193     /**
0194      * @brief Saves the given remote URL to disk and asks the browser to display it
0195      *
0196      * This is used in response to the "Save URL as" entry in the context menu
0197      *
0198      * The URL is saved using the \link KonqInterfaces::DownloaderInterface DownloaderInterface\endlink.
0199      * The browser is asked to display the downloaded URL in a new tab and only if it
0200      * can be embedded. This is to minimize disturbance for the user (which has already
0201      * had to choose the download destination).
0202      *
0203      * @param req the object describing the download request
0204      * @param args the `KParts::OpenUrlArguments` to pass when asking the browser to display the downloaded URL
0205      * @param bArgs the `BrowserArguments` arguments to pass when asking the browser to display the downloaded URL
0206      * @todo Instead of asking the browser to display the downloaded URL, show a message widget at the bottom with
0207      * a button allowing the user to display the file and which disappears automatically after a time. It's similar
0208      * to the way Chrome allows to quickly open a file after downloading it, but it is only done when the user
0209      * explicitly asks to save the URL.
0210      */
0211      void saveUrlToDiskAndDisplay(QWebEngineDownloadRequest *req, const KParts::OpenUrlArguments &args, const BrowserArguments &bArgs);
0212 
0213      /**
0214       * @brief Saves the page currently displayed and opens the local copy
0215       *
0216       * This is used in response to the "Save as" menu entry
0217       * @param req the object describing the download request
0218       */
0219      void saveAs(QWebEngineDownloadRequest *req);
0220 
0221 private:
0222     enum WebEnginePageSecurity { PageUnencrypted, PageEncrypted, PageMixed };
0223 
0224     int m_kioErrorCode;
0225     bool m_ignoreError;
0226 
0227     WebSslInfo m_sslInfo;
0228     QPointer<WebEnginePart> m_part;
0229 
0230     QScopedPointer<KPasswdServerClient> m_passwdServerClient;
0231 
0232 #ifndef REMOTE_DND_NOT_HANDLED_BY_WEBENGINE
0233     /**
0234      * @brief Timer used to decide whether a drop operation is happening
0235      *
0236      * A drop operation is happening if this timer is active
0237      * @see setDropOperationStarted for more details
0238      */
0239     QTimer *m_dropOperationTimer;
0240 #endif
0241 
0242     QMultiHash<QUrl, QWebEngineDownloadRequest*> m_downloadItems;
0243 };
0244 
0245 
0246 /**
0247  * This is a fake implementation of WebEnginePage to workaround the ugly API used
0248  * to request for the creation of a new window from javascript in QtWebEngine. PORTING_TODO
0249  *
0250  * The KPart API for creating new windows requires all the information about the
0251  * new window up front. Unfortunately QWebEnginePage::createWindow function does not
0252  * provide any of these necessary information except for the window type. All
0253  * the other necessary information is emitted as signals instead! Hence, the
0254  * need for this class to collect all of the necessary information, such as
0255  * window name, size and position, before calling KPart's createNewWindow
0256  * function.
0257  */
0258 class NewWindowPage : public WebEnginePage
0259 {
0260     Q_OBJECT
0261 public:
0262     NewWindowPage(WebWindowType windowType, WebEnginePart* part,
0263                   QWidget* parent = nullptr);
0264     ~NewWindowPage() override;
0265 
0266 protected:
0267     bool acceptNavigationRequest(const QUrl& request, NavigationType type, bool isMainFrame) override;
0268 
0269 private Q_SLOTS:
0270     void slotGeometryChangeRequested(const QRect& rect) override;
0271     void slotMenuBarVisibilityChangeRequested(bool visible);
0272     void slotStatusBarVisibilityChangeRequested(bool visible);
0273     void slotToolBarVisibilityChangeRequested(bool visible);
0274     void slotLoadFinished(bool);
0275 
0276 private:
0277     /**
0278      * @brief Decide whether the page is allowed to open a new window requested by javascript or not
0279      * @param url the URL to load in the new window
0280      * @return `true` if the page is allowed to open the new window and `false` if it isn't
0281      */
0282     bool decideHandlingOfJavascripWindow(const QUrl url) const;
0283 
0284 private:
0285     WindowArgs m_windowArgs;
0286     WebWindowType m_type;
0287     bool m_createNewWindow;
0288 };
0289 
0290 #endif // WEBENGINEPAGE_H
0291