aboutsummaryrefslogtreecommitdiff
path: root/src/webengine/webpage.cpp
blob: b2fe79061aaea9d89cee0c7bfa1ea7e98752511c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
 * This file is part of smolbote. It's copyrighted by the contributors recorded
 * in the version control history of the file, available from its original
 * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
 *
 * SPDX-License-Identifier: GPL-3.0
 */

#include "webpage.h"
#include <QLayout>
#include <QMessageBox>
#include <QTimer>
#include <QWebEngineFullScreenRequest>

QString tr_terminationStatus(QWebEnginePage::RenderProcessTerminationStatus status)
{
    switch(status) {
    case QWebEnginePage::NormalTerminationStatus:
        return QObject::tr("The render process terminated normally.");
    case QWebEnginePage::AbnormalTerminationStatus:
        return QObject::tr("The render process terminated with with a non-zero exit status.");
    case QWebEnginePage::CrashedTerminationStatus:
        return QObject::tr("The render process crashed, for example because of a segmentation fault.");
    case QWebEnginePage::KilledTerminationStatus:
        return QObject::tr("The render process was killed, for example by SIGKILL or task manager kill.");
    }
}

QString feature_toString(QWebEnginePage::Feature feature)
{
    switch(feature) {
    case QWebEnginePage::Notifications:
        return QObject::tr("Notifications");
    case QWebEnginePage::Geolocation:
        return QObject::tr("Geolocation");
    case QWebEnginePage::MediaAudioCapture:
        return QObject::tr("Audio Capture");
    case QWebEnginePage::MediaVideoCapture:
        return QObject::tr("Video Capture");
    case QWebEnginePage::MediaAudioVideoCapture:
        return QObject::tr("Audio and Video Capture");
    case QWebEnginePage::MouseLock:
        return QObject::tr("Mouse Lock");
    case QWebEnginePage::DesktopVideoCapture:
        return QObject::tr("Desktop Video Capture");
    case QWebEnginePage::DesktopAudioVideoCapture:
        return QObject::tr("Desktop Audio and Video Capture");
    }
}

WebPage::WebPage(QWebEngineProfile *profile, QObject *parent)
    : QWebEnginePage(profile, parent)
{
    connect(this, &WebPage::fullScreenRequested, this, [](QWebEngineFullScreenRequest request) {
        request.accept();
    });

    connect(this, &QWebEnginePage::featurePermissionRequested, this, &WebPage::featurePermissionDialog);
    connect(this, &QWebEnginePage::renderProcessTerminated, this, &WebPage::renderProcessCrashed);
}

bool WebPage::certificateError(const QWebEngineCertificateError &certificateError)
{
    QMessageBox messageBox;

    messageBox.setWindowTitle(tr("SSL Error"));
    if(certificateError.isOverridable())
        messageBox.setIcon(QMessageBox::Warning);
    else
        messageBox.setIcon(QMessageBox::Critical);

    messageBox.setText(tr("An SSL error has occurred on <strong>%1</strong>").arg(certificateError.url().toString()));
    messageBox.setInformativeText(tr("<p>%1</p>"
                                     "<p>This error %2 be overridden.</p>")
                                      .arg(certificateError.errorDescription(),
                                          certificateError.isOverridable() ? tr("can") : tr("cannot")));
    messageBox.setDetailedText(tr("Error code: %1").arg(certificateError.error()));

    if(certificateError.isOverridable()) {
        messageBox.setStandardButtons(QMessageBox::Ignore | QMessageBox::Abort);
        messageBox.setDefaultButton(QMessageBox::Ignore);
    } else
        messageBox.setStandardButtons(QMessageBox::Abort);

    auto resp = messageBox.exec();

    return resp == QMessageBox::Ignore;
}

#ifdef QTBUG_68224_WORKAROUND
bool WebPage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame)
{
    /* Workaround for https://bugreports.qt.io/browse/QTBUG-68224
     * Only affects 5.11.0; should be fixed in 5.11.1
     */

    auto *layout = this->view()->layout();
    auto count = layout->count();

    if(count > 1) {
        for(int i = 0; i < count; ++i) {
            auto *item = layout->itemAt(i);
            if(item == nullptr)
                continue;
            auto *widget = item->widget();
            if(widget != this->view()->focusProxy()) {
                //qDebug("Removing widget");
                layout->removeWidget(widget);
            }
        }
    }

    return true;
}
#endif

void WebPage::featurePermissionDialog(const QUrl &securityOrigin, QWebEnginePage::Feature feature)
{
    QMessageBox messageBox;

    messageBox.setWindowTitle(tr("Feature permission request"));
    messageBox.setIcon(QMessageBox::Question);
    messageBox.setText(tr("<p>The webpage <strong>%1</strong> has requested permission to access: %2</p>"
                          "<p>Allow this feature?</p>")
                           .arg(securityOrigin.toString(), feature_toString(feature)));

    messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    messageBox.setDefaultButton(QMessageBox::No);

    if(messageBox.exec() == QMessageBox::Yes)
        setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser);
    else
        setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionDeniedByUser);
}

void WebPage::renderProcessCrashed(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode)
{
    if(terminationStatus != QWebEnginePage::NormalTerminationStatus) {
#ifdef QT_DEBUG
        qDebug("render process terminated: [%i] %i", terminationStatus, exitCode);
#endif

        QString page = "<html><body><h1>This tab has crashed!</h1>%message%</body></html>";
        page.replace(QLatin1String("%message%"), QString("<p>%1<br>Exit code is %2.</p>"
                                                         "<p>Press <a href='%3'>here</a> to reload this tab.</p>")
                                                     .arg(tr_terminationStatus(terminationStatus), QString::number(exitCode), this->url().toEncoded()));

        QTimer::singleShot(0, this, [=]() {
            setHtml(page.toUtf8(), url());
        });
    }
}