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"