File indexing completed on 2025-01-26 04:57:25

0001 /*
0002    SPDX-FileCopyrightText: 2016-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "webengineview.h"
0008 #include "checkphishingurl/localdatabasemanager.h"
0009 #include "webenginemanagescript.h"
0010 #include "webenginenavigationrequestinterceptor.h"
0011 #include "webengineviewer_debug.h"
0012 #include <QEvent>
0013 #include <QKeyEvent>
0014 #include <QMouseEvent>
0015 #include <QTimer>
0016 #include <QWheelEvent>
0017 
0018 using namespace WebEngineViewer;
0019 
0020 class WebEngineViewer::WebEngineViewPrivate
0021 {
0022 public:
0023     explicit WebEngineViewPrivate(WebEngineView *q)
0024         : q(q)
0025     {
0026     }
0027 
0028     ~WebEngineViewPrivate()
0029     {
0030         delete mWebEngineNavigatorInterceptor;
0031         mWebEngineNavigatorInterceptor = nullptr;
0032         delete mWebEngineNavigatorInterceptorView;
0033         mWebEngineNavigatorInterceptorView = nullptr;
0034     }
0035 
0036     void renderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus status)
0037     {
0038         switch (status) {
0039         case QWebEnginePage::NormalTerminationStatus:
0040             return;
0041 
0042         case QWebEnginePage::AbnormalTerminationStatus:
0043             qCInfo(WEBENGINEVIEWER_LOG) << "WebEngine render process terminated abnormally";
0044             break;
0045         case QWebEnginePage::CrashedTerminationStatus:
0046             qCInfo(WEBENGINEVIEWER_LOG) << "WebEngine render process crashed";
0047             break;
0048         case QWebEnginePage::KilledTerminationStatus:
0049             qCInfo(WEBENGINEVIEWER_LOG) << "WebEngine render process killed";
0050             break;
0051         }
0052 
0053         // don't get stuck in a loop if the renderer keeps crashing. Five restarts
0054         // is an arbitrary constant.
0055         if (++mCrashCount < 6) {
0056             QTimer::singleShot(0, q, &QWebEngineView::reload);
0057         } else {
0058             // TODO: try to show a sadface page
0059         }
0060     }
0061 
0062     qreal mSavedRelativePosition = -1;
0063     QWidget *mCurrentWidget = nullptr;
0064     WebEngineNavigationRequestInterceptor *mWebEngineNavigatorInterceptor = nullptr;
0065     WebEngineView *mWebEngineNavigatorInterceptorView = nullptr;
0066     LocalDataBaseManager *mPhishingDatabase = nullptr;
0067     int mCrashCount = 0;
0068 
0069 private:
0070     WebEngineView *const q;
0071 };
0072 
0073 WebEngineView::WebEngineView(QWidget *parent)
0074     : QWebEngineView(parent)
0075     , d(new WebEngineViewer::WebEngineViewPrivate(this))
0076 {
0077     installEventFilter(this);
0078 
0079     connect(this, &QWebEngineView::renderProcessTerminated, this, [this](QWebEnginePage::RenderProcessTerminationStatus status) {
0080         d->renderProcessTerminated(status);
0081     });
0082     connect(this, &QWebEngineView::loadFinished, this, [this]() {
0083         // Reset the crash counter if we manage to actually load a page.
0084         // This does not perfectly correspond to "we managed to render
0085         // a page", but it's the best we have
0086         d->mCrashCount = 0;
0087     });
0088 }
0089 
0090 WebEngineView::~WebEngineView() = default;
0091 
0092 void WebEngineView::forwardWheelEvent(QWheelEvent *event)
0093 {
0094     Q_UNUSED(event)
0095 }
0096 
0097 void WebEngineView::forwardKeyPressEvent(QKeyEvent *event)
0098 {
0099     Q_UNUSED(event)
0100 }
0101 
0102 void WebEngineView::forwardKeyReleaseEvent(QKeyEvent *event)
0103 {
0104     Q_UNUSED(event)
0105 }
0106 
0107 void WebEngineView::forwardMousePressEvent(QMouseEvent *event)
0108 {
0109     Q_UNUSED(event)
0110 }
0111 
0112 void WebEngineView::forwardMouseMoveEvent(QMouseEvent *event)
0113 {
0114     Q_UNUSED(event)
0115 }
0116 
0117 void WebEngineView::forwardMouseReleaseEvent(QMouseEvent *event)
0118 {
0119     Q_UNUSED(event)
0120 }
0121 
0122 bool WebEngineView::eventFilter(QObject *obj, QEvent *event)
0123 {
0124     // Keyboard events are sent to parent widget
0125     if (obj == this && event->type() == QEvent::ParentChange && parentWidget()) {
0126         parentWidget()->installEventFilter(this);
0127     }
0128 
0129     // Hack to find widget that receives input events
0130     if (obj == this && event->type() == QEvent::ChildAdded) {
0131         QTimer::singleShot(0, this, [this]() {
0132             if (focusProxy() && d->mCurrentWidget != focusProxy()) {
0133                 d->mCurrentWidget = focusProxy();
0134                 d->mCurrentWidget->installEventFilter(this);
0135             }
0136         });
0137     }
0138 
0139     // Forward events to WebEngineView
0140     if (obj == d->mCurrentWidget) {
0141 #define HANDLE_EVENT(f, t)                                                                                                                                     \
0142     {                                                                                                                                                          \
0143         bool wasAccepted = event->isAccepted();                                                                                                                \
0144         event->setAccepted(false);                                                                                                                             \
0145         f(static_cast<t *>(event));                                                                                                                            \
0146         bool ret = event->isAccepted();                                                                                                                        \
0147         event->setAccepted(wasAccepted);                                                                                                                       \
0148         return ret;                                                                                                                                            \
0149     }
0150 
0151         switch (event->type()) {
0152         case QEvent::KeyPress:
0153             HANDLE_EVENT(forwardKeyPressEvent, QKeyEvent)
0154         case QEvent::KeyRelease:
0155             HANDLE_EVENT(forwardKeyReleaseEvent, QKeyEvent)
0156         case QEvent::MouseButtonPress:
0157             HANDLE_EVENT(forwardMousePressEvent, QMouseEvent)
0158         case QEvent::MouseButtonRelease:
0159             HANDLE_EVENT(forwardMouseReleaseEvent, QMouseEvent)
0160         case QEvent::MouseMove:
0161             HANDLE_EVENT(forwardMouseMoveEvent, QMouseEvent)
0162         case QEvent::Wheel:
0163             HANDLE_EVENT(forwardWheelEvent, QWheelEvent)
0164         default:
0165             break;
0166         }
0167 
0168 #undef HANDLE_EVENT
0169     }
0170     // Block already handled events
0171     if (obj == this) {
0172         switch (event->type()) {
0173         case QEvent::KeyPress:
0174         case QEvent::KeyRelease:
0175         case QEvent::MouseButtonPress:
0176         case QEvent::MouseButtonRelease:
0177         case QEvent::MouseMove:
0178         case QEvent::Wheel:
0179             return true;
0180 
0181         default:
0182             break;
0183         }
0184     }
0185     return QWebEngineView::eventFilter(obj, event);
0186 }
0187 
0188 QWebEngineView *WebEngineView::createWindow(QWebEnginePage::WebWindowType type)
0189 {
0190     Q_UNUSED(type)
0191     delete d->mWebEngineNavigatorInterceptor;
0192     delete d->mWebEngineNavigatorInterceptorView;
0193     d->mWebEngineNavigatorInterceptorView = new WebEngineView();
0194 
0195     d->mWebEngineNavigatorInterceptor = new WebEngineNavigationRequestInterceptor(this->page());
0196     d->mWebEngineNavigatorInterceptorView->setPage(d->mWebEngineNavigatorInterceptor);
0197     return d->mWebEngineNavigatorInterceptorView;
0198 }
0199 
0200 void WebEngineView::clearRelativePosition()
0201 {
0202     d->mSavedRelativePosition = -1;
0203 }
0204 
0205 void WebEngineView::saveRelativePosition()
0206 {
0207     if (d->mSavedRelativePosition != -1) {
0208         d->mSavedRelativePosition = page()->scrollPosition().toPoint().y();
0209     }
0210 }
0211 
0212 qreal WebEngineView::relativePosition() const
0213 {
0214     qCDebug(WEBENGINEVIEWER_LOG) << "Relative Position" << d->mSavedRelativePosition;
0215     return d->mSavedRelativePosition;
0216 }
0217 
0218 LocalDataBaseManager *WebEngineView::phishingDatabase() const
0219 {
0220     if (!d->mPhishingDatabase) {
0221         d->mPhishingDatabase = new LocalDataBaseManager(const_cast<WebEngineView *>(this));
0222         d->mPhishingDatabase->initialize();
0223     }
0224     return d->mPhishingDatabase;
0225 }
0226 
0227 #include "moc_webengineview.cpp"