1
mirror of https://invent.kde.org/network/falkon.git synced 2024-09-22 18:22:10 +02:00
falkonOfficial/src/lib/plugins/clicktoflash.cpp
David Rosca 60b2386a6e Initial port to QtWebEngine
This is first quick port to QtWebEngine, most of advanced features
are not working yet. Please read README.

For now, it will use separate profile directory as well as browser
session, that means you can use both QtWebEngine and QtWebKit versions
at the same time.
2015-01-27 11:01:52 +01:00

327 lines
11 KiB
C++

/* ============================================================
* QupZilla - WebKit based browser
* Copyright (C) 2010-2014 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
/* ============================================================
*
* Copyright (C) 2009 by Benjamin C. Meyer <ben@meyerhome.net>
* Copyright (C) 2010 by Matthieu Gicquel <matgic78@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ============================================================ */
#include "clicktoflash.h"
#include "clickablelabel.h"
#include "mainapplication.h"
#include "pluginproxy.h"
#include "squeezelabelv2.h"
#include "webpage.h"
#include "qztools.h"
#include "browserwindow.h"
#include <QHBoxLayout>
#include <QToolButton>
#include <QFormLayout>
#include <QMenu>
#include <QTimer>
#include <QWebEngineView>
#include <QNetworkRequest>
#if QTWEBENGINE_DISABLED
#include <QWebHitTestResult>
QUrl ClickToFlash::acceptedUrl;
QStringList ClickToFlash::acceptedArgNames;
QStringList ClickToFlash::acceptedArgValues;
ClickToFlash::ClickToFlash(const QUrl &pluginUrl, const QStringList &argumentNames, const QStringList &argumentValues, WebPage* parentPage)
: QWidget()
, m_argumentNames(argumentNames)
, m_argumentValues(argumentValues)
, m_toolButton(0)
, m_layout1(0)
, m_layout2(0)
, m_frame(0)
, m_url(pluginUrl)
, m_page(parentPage)
{
m_layout1 = new QHBoxLayout(this);
m_frame = new QFrame(this);
m_frame->setObjectName("click2flash-frame");
m_frame->setContentsMargins(0, 0, 0, 0);
m_layout2 = new QHBoxLayout(m_frame);
m_toolButton = new QToolButton(this);
m_toolButton->setObjectName("click2flash-toolbutton");
m_toolButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_toolButton->setCursor(Qt::PointingHandCursor);
m_layout2->addWidget(m_toolButton);
m_layout1->addWidget(m_frame);
m_layout1->setContentsMargins(0, 0, 0, 0);
m_layout2->setContentsMargins(0, 0, 0, 0);
connect(m_toolButton, SIGNAL(clicked()), this, SLOT(load()));
setMinimumSize(27, 27);
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequested(QPoint)));
QTimer::singleShot(0, this, SLOT(ensurePluginVisible()));
}
bool ClickToFlash::isAlreadyAccepted(const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues)
{
return (url == acceptedUrl &&
argumentNames == acceptedArgNames &&
argumentValues == acceptedArgValues);
}
void ClickToFlash::ensurePluginVisible()
{
// Well, kind of a dirty workaround, but it works.
// I don't know any other method how to show our plugin
// and adjust it on the proper position in page
// Scheduling adjustingPage rather than actually changing zoomFactor
// right now, as it is CPU intensive when there is lot of click2flash
// objects on page
m_page->scheduleAdjustPage();
}
void ClickToFlash::customContextMenuRequested(const QPoint &pos)
{
QMenu menu;
menu.addAction(tr("Object blocked by ClickToFlash"));
menu.addAction(tr("Show more information about object"), this, SLOT(showInfo()));
menu.addSeparator();
menu.addAction(tr("Delete object"), this, SLOT(hideObject()));
menu.addAction(tr("Add %1 to whitelist").arg(m_url.host()), this, SLOT(toWhitelist()));
menu.actions().at(0)->setEnabled(false);
menu.exec(mapToGlobal(pos));
}
void ClickToFlash::toWhitelist()
{
mApp->plugins()->c2f_addWhitelist(m_url.host());
load();
}
void ClickToFlash::hideObject()
{
findElement();
if (!m_element.isNull()) {
m_element.setStyleProperty("visibility", "hidden");
}
else {
hide();
}
//deleteLater(); //Well, it should be there, but therefore it sometimes crashes
}
void ClickToFlash::findElement()
{
if (!m_toolButton) {
return;
}
QWidget* parent = parentWidget();
QWebEngineView* view = 0;
while (parent) {
if (QWebEngineView* aView = qobject_cast<QWebEngineView*>(parent)) {
view = aView;
break;
}
parent = parent->parentWidget();
}
if (!view) {
return;
}
QPoint objectPos = view->mapFromGlobal(m_toolButton->mapToGlobal(m_toolButton->pos()));
QWebEngineFrame* objectFrame = view->page()->frameAt(objectPos);
QWebHitTestResult hitResult;
QWebElement hitElement;
if (objectFrame) {
hitResult = objectFrame->hitTestContent(objectPos);
hitElement = hitResult.element();
}
if (!hitElement.isNull() && (hitElement.tagName().compare("embed", Qt::CaseInsensitive) == 0 ||
hitElement.tagName().compare("object", Qt::CaseInsensitive) == 0)) {
m_element = hitElement;
return;
}
// HitTestResult failed, trying to find element by src
// attribute in elements at all frames on page (less accurate)
QList<QWebEngineFrame*> frames;
frames.append(objectFrame);
frames.append(view->page()->mainFrame());
while (!frames.isEmpty()) {
QWebEngineFrame* frame = frames.takeFirst();
if (!frame) {
continue;
}
QWebElement docElement = frame->documentElement();
QWebElementCollection elements;
elements.append(docElement.findAll(QLatin1String("embed")));
elements.append(docElement.findAll(QLatin1String("object")));
foreach (const QWebElement &element, elements) {
if (!checkElement(element) && !checkUrlOnElement(element)) {
continue;
}
m_element = element;
return;
}
frames += frame->childFrames();
}
}
void ClickToFlash::load()
{
findElement();
if (m_element.isNull()) {
qWarning("Click2Flash: Cannot find Flash object.");
}
else {
/*
Old code caused sometimes flashing of the whole browser window and then somehow
ruined rendering of opacity effects, etc..
QWebElement substitute = m_element.clone();
substitute.setAttribute(QLatin1String("type"), "application/futuresplash");
m_element.replace(substitute);
So asynchronous JavaScript code is used to remove element from page and then substitute
it with unblocked Flash. The JavaScript code is:
var qz_c2f_clone = this.cloneNode(true);
var qz_c2f_parentNode = this.parentNode;
var qz_c2f_substituteElement = document.createElement(this.tagName);
qz_c2f_substituteElement.width = this.width;
qz_c2f_substituteElement.height = this.height;
qz_c2f_substituteElement.type = "application/futuresplash";
this.parentNode.replaceChild(qz_c2f_substituteElement, this);
setTimeout(function(){
qz_c2f_parentNode.replaceChild(qz_c2f_clone, qz_c2f_substituteElement);
}, 250);
*/
acceptedUrl = m_url;
acceptedArgNames = m_argumentNames;
acceptedArgValues = m_argumentValues;
QString js = "var qz_c2f_clone=this.cloneNode(true);var qz_c2f_parentNode=this.parentNode;"
"var qz_c2f_substituteElement=document.createElement(this.tagName);"
"qz_c2f_substituteElement.width=this.width;qz_c2f_substituteElement.height=this.height;"
"qz_c2f_substituteElement.type=\"application/futuresplash\";"
"this.parentNode.replaceChild(qz_c2f_substituteElement,this);setTimeout(function(){"
"qz_c2f_parentNode.replaceChild(qz_c2f_clone,qz_c2f_substituteElement);},250);";
m_element.evaluateJavaScript(js);
}
}
bool ClickToFlash::checkUrlOnElement(QWebElement el)
{
QString checkString = el.attribute("src");
if (checkString.isEmpty()) {
checkString = el.attribute("data");
}
if (checkString.isEmpty()) {
checkString = el.attribute("value");
}
checkString = m_page->url().resolved(QUrl(checkString)).toString(QUrl::RemoveQuery);
return m_url.toEncoded().contains(checkString.toUtf8());
}
bool ClickToFlash::checkElement(QWebElement el)
{
if (m_argumentNames == el.attributeNames()) {
foreach (const QString &name, m_argumentNames) {
if (m_argumentValues.indexOf(el.attribute(name)) == -1) {
return false;
}
}
return true;
}
return false;
}
void ClickToFlash::showInfo()
{
QWidget* widg = new QWidget();
widg->setAttribute(Qt::WA_DeleteOnClose);
widg->setWindowTitle(tr("Flash Object"));
QFormLayout* lay = new QFormLayout(widg);
QLabel* attrib = new QLabel(tr("<b>Attribute Name</b>"));
QLabel* value = new QLabel(tr("<b>Value</b>"));
if (isRightToLeft()) {
widg->setLayoutDirection(Qt::LeftToRight);
attrib->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
value->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
}
lay->addRow(attrib, value);
int i = 0;
foreach (const QString &name, m_argumentNames) {
QString value = m_argumentValues.at(i);
SqueezeLabelV2* valueLabel = new SqueezeLabelV2(value);
valueLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
lay->addRow(new SqueezeLabelV2(name), valueLabel);
i++;
}
if (i == 0) {
lay->addRow(new QLabel(tr("No more information available.")));
}
widg->setMaximumHeight(500);
QzTools::centerWidgetToParent(widg, m_page->view());
widg->show();
}
#endif