mirror of
https://invent.kde.org/network/falkon.git
synced 2024-11-11 01:22:10 +01:00
AdBlock: Use one cache for all subscriptions
Added new class AdBlockMatcher that holds the cache of all subscriptions with rules. This moves the matching logic from AdBlockSubscription into separate class. It also fixes issue that CSS exception rules weren't able to affect rules from different subscription.
This commit is contained in:
parent
613d18ed16
commit
a0dd1ddcb7
|
@ -50,11 +50,11 @@
|
|||
#include <QNetworkRequest>
|
||||
#include <QTimer>
|
||||
|
||||
AdBlockBlockedNetworkReply::AdBlockBlockedNetworkReply(const AdBlockSubscription* subscription, const AdBlockRule* rule, QObject* parent)
|
||||
AdBlockBlockedNetworkReply::AdBlockBlockedNetworkReply(const AdBlockRule* rule, QObject* parent)
|
||||
: QNetworkReply(parent)
|
||||
{
|
||||
setOperation(QNetworkAccessManager::GetOperation);
|
||||
setError(QNetworkReply::ContentAccessDenied, QString("AdBlock: %1 (%2)").arg(subscription->title(), rule->filter()));
|
||||
setError(QNetworkReply::ContentAccessDenied, QString("AdBlock: %1 (%2)").arg(rule->subscription()->title(), rule->filter()));
|
||||
|
||||
open(QIODevice::ReadOnly);
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ class QUPZILLA_EXPORT AdBlockBlockedNetworkReply : public QNetworkReply
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AdBlockBlockedNetworkReply(const AdBlockSubscription* subscription, const AdBlockRule* rule, QObject* parent = 0);
|
||||
AdBlockBlockedNetworkReply(const AdBlockRule* rule, QObject* parent = 0);
|
||||
void abort() {}
|
||||
|
||||
void setRequest(const QNetworkRequest &request);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* ============================================================ */
|
||||
#include "adblockmanager.h"
|
||||
#include "adblockdialog.h"
|
||||
#include "adblockmatcher.h"
|
||||
#include "adblocksubscription.h"
|
||||
#include "adblockblockednetworkreply.h"
|
||||
#include "datapaths.h"
|
||||
|
@ -45,6 +46,7 @@ AdBlockManager::AdBlockManager(QObject* parent)
|
|||
, m_loaded(false)
|
||||
, m_enabled(true)
|
||||
, m_useLimitedEasyList(true)
|
||||
, m_matcher(new AdBlockMatcher(this))
|
||||
{
|
||||
load();
|
||||
}
|
||||
|
@ -92,12 +94,10 @@ QNetworkReply* AdBlockManager::block(const QNetworkRequest &request)
|
|||
const QString urlDomain = request.url().host().toLower();
|
||||
const QString urlScheme = request.url().scheme().toLower();
|
||||
|
||||
if (!isEnabled() || !canRunOnScheme(urlScheme)) {
|
||||
if (!isEnabled() || !canRunOnScheme(urlScheme))
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach (AdBlockSubscription* subscription, m_subscriptions) {
|
||||
const AdBlockRule* blockedRule = subscription->match(request, urlDomain, urlString);
|
||||
const AdBlockRule* blockedRule = m_matcher->match(request, urlDomain, urlString);
|
||||
|
||||
if (blockedRule) {
|
||||
QVariant v = request.attribute((QNetworkRequest::Attribute)(QNetworkRequest::User + 100));
|
||||
|
@ -110,7 +110,7 @@ QNetworkReply* AdBlockManager::block(const QNetworkRequest &request)
|
|||
webPage->addAdBlockRule(blockedRule, request.url());
|
||||
}
|
||||
|
||||
AdBlockBlockedNetworkReply* reply = new AdBlockBlockedNetworkReply(subscription, blockedRule, this);
|
||||
AdBlockBlockedNetworkReply* reply = new AdBlockBlockedNetworkReply(blockedRule, this);
|
||||
reply->setRequest(request);
|
||||
|
||||
#ifdef ADBLOCK_DEBUG
|
||||
|
@ -119,7 +119,6 @@ QNetworkReply* AdBlockManager::block(const QNetworkRequest &request)
|
|||
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ADBLOCK_DEBUG
|
||||
qDebug() << timer.elapsed() << request.url();
|
||||
|
@ -252,7 +251,6 @@ void AdBlockManager::load()
|
|||
AdBlockSubscription* subscription = new AdBlockSubscription(title, this);
|
||||
subscription->setUrl(url);
|
||||
subscription->setFilePath(absolutePath);
|
||||
connect(subscription, SIGNAL(subscriptionUpdated()), mApp, SLOT(reloadUserStyleSheet()));
|
||||
|
||||
m_subscriptions.append(subscription);
|
||||
}
|
||||
|
@ -262,7 +260,6 @@ void AdBlockManager::load()
|
|||
AdBlockSubscription* easyList = new AdBlockSubscription(tr("EasyList"), this);
|
||||
easyList->setUrl(QUrl(ADBLOCK_EASYLIST_URL));
|
||||
easyList->setFilePath(DataPaths::currentProfilePath() + QLatin1String("/adblock/easylist.txt"));
|
||||
connect(easyList, SIGNAL(subscriptionUpdated()), mApp, SLOT(reloadUserStyleSheet()));
|
||||
|
||||
m_subscriptions.prepend(easyList);
|
||||
}
|
||||
|
@ -270,11 +267,13 @@ void AdBlockManager::load()
|
|||
// Append CustomList
|
||||
AdBlockCustomList* customList = new AdBlockCustomList(this);
|
||||
m_subscriptions.append(customList);
|
||||
connect(customList, SIGNAL(subscriptionEdited()), mApp, SLOT(reloadUserStyleSheet()));
|
||||
|
||||
// Load all subscriptions
|
||||
foreach (AdBlockSubscription* subscription, m_subscriptions) {
|
||||
subscription->loadSubscription(m_disabledRules);
|
||||
|
||||
connect(subscription, SIGNAL(subscriptionUpdated()), mApp, SLOT(reloadUserStyleSheet()));
|
||||
connect(subscription, SIGNAL(subscriptionChanged()), m_matcher, SLOT(update()));
|
||||
}
|
||||
|
||||
if (lastUpdate.addDays(5) < QDateTime::currentDateTime()) {
|
||||
|
@ -285,6 +284,7 @@ void AdBlockManager::load()
|
|||
qDebug() << "AdBlock loaded in" << timer.elapsed();
|
||||
#endif
|
||||
|
||||
m_matcher->update();
|
||||
m_loaded = true;
|
||||
}
|
||||
|
||||
|
@ -348,57 +348,24 @@ void AdBlockManager::setUseLimitedEasyList(bool useLimited)
|
|||
|
||||
bool AdBlockManager::canBeBlocked(const QUrl &url) const
|
||||
{
|
||||
foreach (AdBlockSubscription* subscription, m_subscriptions) {
|
||||
if (subscription->adBlockDisabledForUrl(url)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return !m_matcher->adBlockDisabledForUrl(url);
|
||||
}
|
||||
|
||||
QString AdBlockManager::elementHidingRules() const
|
||||
{
|
||||
if (!m_enabled) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString rules;
|
||||
|
||||
foreach (AdBlockSubscription* subscription, m_subscriptions) {
|
||||
rules.append(subscription->elementHidingRules());
|
||||
}
|
||||
|
||||
return rules;
|
||||
return m_matcher->elementHidingRules();
|
||||
}
|
||||
|
||||
QString AdBlockManager::elementHidingRulesForDomain(const QUrl &url) const
|
||||
{
|
||||
if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url)) {
|
||||
if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url))
|
||||
return QString();
|
||||
}
|
||||
|
||||
// Acid3 doesn't like the way element hiding rules are embedded into page
|
||||
if (url.host() == QLatin1String("acid3.acidtests.org")) {
|
||||
if (url.host() == QLatin1String("acid3.acidtests.org"))
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString rules;
|
||||
|
||||
foreach (AdBlockSubscription* subscription, m_subscriptions) {
|
||||
if (subscription->elemHideDisabledForUrl(url)) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
rules.append(subscription->elementHidingRulesForDomain(url.host()));
|
||||
}
|
||||
|
||||
// Remove last ","
|
||||
if (!rules.isEmpty()) {
|
||||
rules = rules.left(rules.size() - 1);
|
||||
}
|
||||
|
||||
return rules;
|
||||
return m_matcher->elementHidingRulesForDomain(url.host());
|
||||
}
|
||||
|
||||
AdBlockSubscription* AdBlockManager::subscriptionByName(const QString &name) const
|
||||
|
|
|
@ -28,7 +28,9 @@ class QUrl;
|
|||
class QNetworkReply;
|
||||
class QNetworkRequest;
|
||||
|
||||
class AdBlockRule;
|
||||
class AdBlockDialog;
|
||||
class AdBlockMatcher;
|
||||
class AdBlockCustomList;
|
||||
class AdBlockSubscription;
|
||||
|
||||
|
@ -87,6 +89,7 @@ private:
|
|||
bool m_useLimitedEasyList;
|
||||
|
||||
QList<AdBlockSubscription*> m_subscriptions;
|
||||
AdBlockMatcher* m_matcher;
|
||||
QStringList m_disabledRules;
|
||||
|
||||
QPointer<AdBlockDialog> m_adBlockDialog;
|
||||
|
|
228
src/lib/adblock/adblockmatcher.cpp
Normal file
228
src/lib/adblock/adblockmatcher.cpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
/* ============================================================
|
||||
* QupZilla - WebKit based browser
|
||||
* Copyright (C) 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/>.
|
||||
* ============================================================ */
|
||||
#include "adblockmatcher.h"
|
||||
#include "adblockmanager.h"
|
||||
#include "adblockrule.h"
|
||||
#include "adblocksubscription.h"
|
||||
|
||||
AdBlockMatcher::AdBlockMatcher(AdBlockManager* manager)
|
||||
: QObject(manager)
|
||||
, m_manager(manager)
|
||||
{
|
||||
connect(manager, SIGNAL(enabledChanged(bool)), this, SLOT(enabledChanged(bool)));
|
||||
}
|
||||
|
||||
AdBlockMatcher::~AdBlockMatcher()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
const AdBlockRule* AdBlockMatcher::match(const QNetworkRequest &request, const QString &urlDomain, const QString &urlString) const
|
||||
{
|
||||
// Exception rules
|
||||
if (m_networkExceptionTree.find(request, urlDomain, urlString))
|
||||
return 0;
|
||||
|
||||
int count = m_networkExceptionRules.count();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const AdBlockRule* rule = m_networkExceptionRules.at(i);
|
||||
if (rule->networkMatch(request, urlDomain, urlString))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Block rules
|
||||
if (const AdBlockRule* rule = m_networkBlockTree.find(request, urlDomain, urlString))
|
||||
return rule;
|
||||
|
||||
count = m_networkBlockRules.count();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const AdBlockRule* rule = m_networkBlockRules.at(i);
|
||||
if (rule->networkMatch(request, urlDomain, urlString))
|
||||
return rule;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AdBlockMatcher::adBlockDisabledForUrl(const QUrl &url) const
|
||||
{
|
||||
int count = m_documentRules.count();
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
if (m_documentRules.at(i)->urlMatch(url))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AdBlockMatcher::elemHideDisabledForUrl(const QUrl &url) const
|
||||
{
|
||||
if (adBlockDisabledForUrl(url))
|
||||
return true;
|
||||
|
||||
int count = m_elemhideRules.count();
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
if (m_elemhideRules.at(i)->urlMatch(url))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString AdBlockMatcher::elementHidingRules() const
|
||||
{
|
||||
return m_elementHidingRules;
|
||||
}
|
||||
|
||||
QString AdBlockMatcher::elementHidingRulesForDomain(const QString &domain) const
|
||||
{
|
||||
QString rules;
|
||||
int addedRulesCount = 0;
|
||||
int count = m_domainRestrictedCssRules.count();
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const AdBlockRule* rule = m_domainRestrictedCssRules.at(i);
|
||||
if (!rule->matchDomain(domain))
|
||||
continue;
|
||||
|
||||
if (Q_UNLIKELY(addedRulesCount == 1000)) {
|
||||
rules.append(rule->cssSelector());
|
||||
rules.append(QL1S("{display:none !important;}\n"));
|
||||
addedRulesCount = 0;
|
||||
}
|
||||
else {
|
||||
rules.append(rule->cssSelector() + QLatin1Char(','));
|
||||
addedRulesCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (addedRulesCount != 0) {
|
||||
rules = rules.left(rules.size() - 1);
|
||||
rules.append(QL1S("{display:none !important;}\n"));
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
void AdBlockMatcher::update()
|
||||
{
|
||||
clear();
|
||||
|
||||
QHash<QString, const AdBlockRule*> cssRulesHash;
|
||||
QVector<const AdBlockRule*> exceptionCssRules;
|
||||
|
||||
foreach (AdBlockSubscription* subscription, m_manager->subscriptions()) {
|
||||
foreach (const AdBlockRule* rule, subscription->allRules()) {
|
||||
// Don't add internally disabled rules to cache
|
||||
if (rule->isInternalDisabled())
|
||||
continue;
|
||||
|
||||
if (rule->isCssRule()) {
|
||||
// We will add only enabled css rules to cache, because there is no enabled/disabled
|
||||
// check on match. They are directly embedded to pages.
|
||||
if (!rule->isEnabled())
|
||||
continue;
|
||||
|
||||
if (rule->isException())
|
||||
exceptionCssRules.append(rule);
|
||||
else
|
||||
cssRulesHash.insert(rule->cssSelector(), rule);
|
||||
}
|
||||
else if (rule->isDocument()) {
|
||||
m_documentRules.append(rule);
|
||||
}
|
||||
else if (rule->isElemhide()) {
|
||||
m_elemhideRules.append(rule);
|
||||
}
|
||||
else if (rule->isException()) {
|
||||
if (!m_networkExceptionTree.add(rule))
|
||||
m_networkExceptionRules.append(rule);
|
||||
}
|
||||
else {
|
||||
if (!m_networkBlockTree.add(rule))
|
||||
m_networkBlockRules.append(rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const AdBlockRule* rule, exceptionCssRules) {
|
||||
const AdBlockRule* originalRule = cssRulesHash.value(rule->cssSelector());
|
||||
|
||||
// If we don't have this selector, the exception does nothing
|
||||
if (!originalRule)
|
||||
continue;
|
||||
|
||||
AdBlockRule* copiedRule = originalRule->copy();
|
||||
copiedRule->m_options |= AdBlockRule::DomainRestrictedOption;
|
||||
copiedRule->m_blockedDomains.append(rule->m_allowedDomains);
|
||||
|
||||
cssRulesHash[rule->cssSelector()] = copiedRule;
|
||||
m_createdRules.append(copiedRule);
|
||||
}
|
||||
|
||||
// Apparently, excessive amount of selectors for one CSS rule is not what WebKit likes.
|
||||
// (In my testings, 4931 is the number that makes it crash)
|
||||
// So let's split it by 1000 selectors...
|
||||
int hidingRulesCount = 0;
|
||||
|
||||
QHashIterator<QString, const AdBlockRule*> it(cssRulesHash);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
const AdBlockRule* rule = it.value();
|
||||
|
||||
if (rule->isDomainRestricted()) {
|
||||
m_domainRestrictedCssRules.append(rule);
|
||||
}
|
||||
else if (Q_UNLIKELY(hidingRulesCount == 1000)) {
|
||||
m_elementHidingRules.append(rule->cssSelector());
|
||||
m_elementHidingRules.append(QL1S("{display:none !important;} "));
|
||||
hidingRulesCount = 0;
|
||||
}
|
||||
else {
|
||||
m_elementHidingRules.append(rule->cssSelector() + QLatin1Char(','));
|
||||
hidingRulesCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (hidingRulesCount != 0) {
|
||||
m_elementHidingRules = m_elementHidingRules.left(m_elementHidingRules.size() - 1);
|
||||
m_elementHidingRules.append(QL1S("{display:none !important;} "));
|
||||
}
|
||||
}
|
||||
|
||||
void AdBlockMatcher::clear()
|
||||
{
|
||||
m_networkExceptionTree.clear();
|
||||
m_networkExceptionRules.clear();
|
||||
m_networkBlockTree.clear();
|
||||
m_networkBlockRules.clear();
|
||||
m_domainRestrictedCssRules.clear();
|
||||
m_elementHidingRules.clear();
|
||||
m_documentRules.clear();
|
||||
m_elemhideRules.clear();
|
||||
qDeleteAll(m_createdRules);
|
||||
m_createdRules.clear();
|
||||
}
|
||||
|
||||
void AdBlockMatcher::enabledChanged(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
update();
|
||||
else
|
||||
clear();
|
||||
}
|
66
src/lib/adblock/adblockmatcher.h
Normal file
66
src/lib/adblock/adblockmatcher.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* ============================================================
|
||||
* QupZilla - WebKit based browser
|
||||
* Copyright (C) 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/>.
|
||||
* ============================================================ */
|
||||
#ifndef ADBLOCKMATCHER_H
|
||||
#define ADBLOCKMATCHER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "qzcommon.h"
|
||||
#include "adblocksearchtree.h"
|
||||
|
||||
class AdBlockManager;
|
||||
|
||||
class QUPZILLA_EXPORT AdBlockMatcher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AdBlockMatcher(AdBlockManager* manager);
|
||||
~AdBlockMatcher();
|
||||
|
||||
const AdBlockRule* match(const QNetworkRequest &request, const QString &urlDomain, const QString &urlString) const;
|
||||
|
||||
bool adBlockDisabledForUrl(const QUrl &url) const;
|
||||
bool elemHideDisabledForUrl(const QUrl &url) const;
|
||||
|
||||
QString elementHidingRules() const;
|
||||
QString elementHidingRulesForDomain(const QString &domain) const;
|
||||
|
||||
public slots:
|
||||
void update();
|
||||
void clear();
|
||||
|
||||
private slots:
|
||||
void enabledChanged(bool enabled);
|
||||
|
||||
private:
|
||||
AdBlockManager* m_manager;
|
||||
|
||||
QVector<AdBlockRule*> m_createdRules;
|
||||
QVector<const AdBlockRule*> m_networkExceptionRules;
|
||||
QVector<const AdBlockRule*> m_networkBlockRules;
|
||||
QVector<const AdBlockRule*> m_domainRestrictedCssRules;
|
||||
QVector<const AdBlockRule*> m_documentRules;
|
||||
QVector<const AdBlockRule*> m_elemhideRules;
|
||||
|
||||
QString m_elementHidingRules;
|
||||
AdBlockSearchTree m_networkBlockTree;
|
||||
AdBlockSearchTree m_networkExceptionTree;
|
||||
};
|
||||
|
||||
#endif // ADBLOCKMATCHER_H
|
|
@ -169,6 +169,7 @@ private:
|
|||
// Use dynamic allocation to save memory
|
||||
RegExp* m_regExp;
|
||||
|
||||
friend class AdBlockMatcher;
|
||||
friend class AdBlockSearchTree;
|
||||
friend class AdBlockSubscription;
|
||||
};
|
||||
|
|
|
@ -128,8 +128,6 @@ void AdBlockSubscription::loadSubscription(const QStringList &disabledRules)
|
|||
m_rules.append(rule);
|
||||
}
|
||||
|
||||
populateCache();
|
||||
|
||||
// Initial update
|
||||
if (m_rules.isEmpty() && !m_updated) {
|
||||
QTimer::singleShot(0, this, SLOT(updateSubscription()));
|
||||
|
@ -176,7 +174,9 @@ void AdBlockSubscription::subscriptionDownloaded()
|
|||
}
|
||||
|
||||
loadSubscription(AdBlockManager::instance()->disabledRules());
|
||||
|
||||
emit subscriptionUpdated();
|
||||
emit subscriptionChanged();
|
||||
}
|
||||
|
||||
bool AdBlockSubscription::saveDownloadedData(const QByteArray &data)
|
||||
|
@ -210,103 +210,6 @@ bool AdBlockSubscription::saveDownloadedData(const QByteArray &data)
|
|||
return true;
|
||||
}
|
||||
|
||||
const AdBlockRule* AdBlockSubscription::match(const QNetworkRequest &request, const QString &urlDomain, const QString &urlString) const
|
||||
{
|
||||
// Exception rules
|
||||
if (m_networkExceptionTree.find(request, urlDomain, urlString)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = m_networkExceptionRules.count();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const AdBlockRule* rule = m_networkExceptionRules.at(i);
|
||||
if (rule->networkMatch(request, urlDomain, urlString)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Block rules
|
||||
if (const AdBlockRule* rule = m_networkBlockTree.find(request, urlDomain, urlString)) {
|
||||
return rule;
|
||||
}
|
||||
|
||||
count = m_networkBlockRules.count();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const AdBlockRule* rule = m_networkBlockRules.at(i);
|
||||
if (rule->networkMatch(request, urlDomain, urlString)) {
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AdBlockSubscription::adBlockDisabledForUrl(const QUrl &url) const
|
||||
{
|
||||
int count = m_documentRules.count();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const AdBlockRule* rule = m_documentRules.at(i);
|
||||
if (rule->urlMatch(url)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AdBlockSubscription::elemHideDisabledForUrl(const QUrl &url) const
|
||||
{
|
||||
if (adBlockDisabledForUrl(url)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int count = m_elemhideRules.count();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const AdBlockRule* rule = m_elemhideRules.at(i);
|
||||
if (rule->urlMatch(url)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString AdBlockSubscription::elementHidingRules() const
|
||||
{
|
||||
return m_elementHidingRules;
|
||||
}
|
||||
|
||||
QString AdBlockSubscription::elementHidingRulesForDomain(const QString &domain) const
|
||||
{
|
||||
QString rules;
|
||||
|
||||
int addedRulesCount = 0;
|
||||
int count = m_domainRestrictedCssRules.count();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const AdBlockRule* rule = m_domainRestrictedCssRules.at(i);
|
||||
if (!rule->matchDomain(domain)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Q_UNLIKELY(addedRulesCount == 1000)) {
|
||||
rules.append(rule->cssSelector());
|
||||
rules.append("{display:none !important;}\n");
|
||||
addedRulesCount = 0;
|
||||
}
|
||||
else {
|
||||
rules.append(rule->cssSelector() + QLatin1Char(','));
|
||||
addedRulesCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (addedRulesCount != 0) {
|
||||
rules = rules.left(rules.size() - 1);
|
||||
rules.append("{display:none !important;}\n");
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
const AdBlockRule* AdBlockSubscription::rule(int offset) const
|
||||
{
|
||||
if (!QzTools::containsIndex(m_rules, offset)) {
|
||||
|
@ -331,10 +234,10 @@ const AdBlockRule* AdBlockSubscription::enableRule(int offset)
|
|||
rule->setEnabled(true);
|
||||
AdBlockManager::instance()->removeDisabledRule(rule->filter());
|
||||
|
||||
if (rule->isCssRule()) {
|
||||
populateCache();
|
||||
emit subscriptionChanged();
|
||||
|
||||
if (rule->isCssRule())
|
||||
mApp->reloadUserStyleSheet();
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
@ -349,10 +252,10 @@ const AdBlockRule* AdBlockSubscription::disableRule(int offset)
|
|||
rule->setEnabled(false);
|
||||
AdBlockManager::instance()->addDisabledRule(rule->filter());
|
||||
|
||||
if (rule->isCssRule()) {
|
||||
populateCache();
|
||||
emit subscriptionChanged();
|
||||
|
||||
if (rule->isCssRule())
|
||||
mApp->reloadUserStyleSheet();
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
@ -386,112 +289,6 @@ const AdBlockRule* AdBlockSubscription::replaceRule(AdBlockRule* rule, int offse
|
|||
return 0;
|
||||
}
|
||||
|
||||
void AdBlockSubscription::populateCache()
|
||||
{
|
||||
m_networkExceptionTree.clear();
|
||||
m_networkExceptionRules.clear();
|
||||
m_networkBlockTree.clear();
|
||||
m_networkBlockRules.clear();
|
||||
m_domainRestrictedCssRules.clear();
|
||||
m_elementHidingRules.clear();
|
||||
m_documentRules.clear();
|
||||
m_elemhideRules.clear();
|
||||
|
||||
qDeleteAll(m_createdRules);
|
||||
m_createdRules.clear();
|
||||
|
||||
QHash<QString, const AdBlockRule*> cssRulesHash;
|
||||
QVector<const AdBlockRule*> exceptionCssRules;
|
||||
|
||||
int count = m_rules.count();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const AdBlockRule* rule = m_rules.at(i);
|
||||
|
||||
// Don't add internally disabled rules to cache
|
||||
if (rule->isInternalDisabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule->isCssRule()) {
|
||||
// We will add only enabled css rules to cache, because there is no enabled/disabled
|
||||
// check on match. They are directly embedded to pages.
|
||||
if (!rule->isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule->isException()) {
|
||||
exceptionCssRules.append(rule);
|
||||
}
|
||||
else {
|
||||
cssRulesHash.insert(rule->cssSelector(), rule);
|
||||
}
|
||||
}
|
||||
else if (rule->isDocument()) {
|
||||
m_documentRules.append(rule);
|
||||
}
|
||||
else if (rule->isElemhide()) {
|
||||
m_elemhideRules.append(rule);
|
||||
}
|
||||
else if (rule->isException()) {
|
||||
if (!m_networkExceptionTree.add(rule)) {
|
||||
m_networkExceptionRules.append(rule);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!m_networkBlockTree.add(rule)) {
|
||||
m_networkBlockRules.append(rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count = exceptionCssRules.count();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const AdBlockRule* rule = exceptionCssRules.at(i);
|
||||
const AdBlockRule* originalRule = cssRulesHash.value(rule->cssSelector());
|
||||
|
||||
// If we don't have this selector, the exception does nothing
|
||||
if (!originalRule) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AdBlockRule* copiedRule = originalRule->copy();
|
||||
copiedRule->m_options |= AdBlockRule::DomainRestrictedOption;
|
||||
copiedRule->m_blockedDomains.append(rule->m_allowedDomains);
|
||||
|
||||
cssRulesHash[rule->cssSelector()] = copiedRule;
|
||||
m_createdRules.append(copiedRule);
|
||||
}
|
||||
|
||||
// Apparently, excessive amount of selectors for one CSS rule is not what WebKit likes.
|
||||
// (In my testings, 4931 is the number that makes it crash)
|
||||
// So let's split it by 1000 selectors...
|
||||
int hidingRulesCount = 0;
|
||||
|
||||
QHashIterator<QString, const AdBlockRule*> it(cssRulesHash);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
const AdBlockRule* rule = it.value();
|
||||
|
||||
if (rule->isDomainRestricted()) {
|
||||
m_domainRestrictedCssRules.append(rule);
|
||||
}
|
||||
else if (Q_UNLIKELY(hidingRulesCount == 1000)) {
|
||||
m_elementHidingRules.append(rule->cssSelector());
|
||||
m_elementHidingRules.append(QL1S("{display:none !important;} "));
|
||||
hidingRulesCount = 0;
|
||||
}
|
||||
else {
|
||||
m_elementHidingRules.append(rule->cssSelector() + QLatin1Char(','));
|
||||
hidingRulesCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (hidingRulesCount != 0) {
|
||||
m_elementHidingRules = m_elementHidingRules.left(m_elementHidingRules.size() - 1);
|
||||
m_elementHidingRules.append(QL1S("{display:none !important;} "));
|
||||
}
|
||||
}
|
||||
|
||||
AdBlockSubscription::~AdBlockSubscription()
|
||||
{
|
||||
qDeleteAll(m_rules);
|
||||
|
@ -519,12 +316,13 @@ void AdBlockCustomList::loadSubscription(const QStringList &disabledRules)
|
|||
QFile file(filePath());
|
||||
if (file.open(QFile::WriteOnly | QFile::Append)) {
|
||||
QTextStream stream(&file);
|
||||
stream.setCodec("UTF-8");
|
||||
|
||||
if (!rules.contains(ddg1))
|
||||
stream << ddg1;
|
||||
if (!rules.contains(ddg1 + QL1S("\n")))
|
||||
stream << ddg1 << endl;
|
||||
|
||||
if (!rules.contains(ddg2))
|
||||
stream << ddg2;
|
||||
if (!rules.contains(QL1S("\n") + ddg2))
|
||||
stream << ddg2 << endl;
|
||||
}
|
||||
file.close();
|
||||
|
||||
|
@ -590,9 +388,11 @@ bool AdBlockCustomList::removeFilter(const QString &filter)
|
|||
int AdBlockCustomList::addRule(AdBlockRule* rule)
|
||||
{
|
||||
m_rules.append(rule);
|
||||
populateCache();
|
||||
|
||||
emit subscriptionEdited();
|
||||
emit subscriptionChanged();
|
||||
|
||||
if (rule->isCssRule())
|
||||
mApp->reloadUserStyleSheet();
|
||||
|
||||
return m_rules.count() - 1;
|
||||
}
|
||||
|
@ -607,9 +407,11 @@ bool AdBlockCustomList::removeRule(int offset)
|
|||
const QString filter = rule->filter();
|
||||
|
||||
m_rules.remove(offset);
|
||||
populateCache();
|
||||
|
||||
emit subscriptionEdited();
|
||||
emit subscriptionChanged();
|
||||
|
||||
if (rule->isCssRule())
|
||||
mApp->reloadUserStyleSheet();
|
||||
|
||||
AdBlockManager::instance()->removeDisabledRule(filter);
|
||||
|
||||
|
@ -623,12 +425,14 @@ const AdBlockRule* AdBlockCustomList::replaceRule(AdBlockRule* rule, int offset)
|
|||
return 0;
|
||||
}
|
||||
|
||||
delete m_rules.at(offset);
|
||||
|
||||
AdBlockRule* oldRule = m_rules.at(offset);
|
||||
m_rules[offset] = rule;
|
||||
populateCache();
|
||||
|
||||
emit subscriptionEdited();
|
||||
emit subscriptionChanged();
|
||||
|
||||
if (rule->isCssRule() || oldRule->isCssRule())
|
||||
mApp->reloadUserStyleSheet();
|
||||
|
||||
delete oldRule;
|
||||
return m_rules[offset];
|
||||
}
|
||||
|
|
|
@ -77,14 +77,6 @@ public:
|
|||
virtual void loadSubscription(const QStringList &disabledRules);
|
||||
virtual void saveSubscription();
|
||||
|
||||
const AdBlockRule* match(const QNetworkRequest &request, const QString &urlDomain, const QString &urlString) const;
|
||||
|
||||
bool adBlockDisabledForUrl(const QUrl &url) const;
|
||||
bool elemHideDisabledForUrl(const QUrl &url) const;
|
||||
|
||||
QString elementHidingRules() const;
|
||||
QString elementHidingRulesForDomain(const QString &domain) const;
|
||||
|
||||
const AdBlockRule* rule(int offset) const;
|
||||
QVector<AdBlockRule*> allRules() const;
|
||||
|
||||
|
@ -102,6 +94,7 @@ public slots:
|
|||
void updateSubscription();
|
||||
|
||||
signals:
|
||||
void subscriptionChanged();
|
||||
void subscriptionUpdated();
|
||||
void subscriptionError(const QString &message);
|
||||
|
||||
|
@ -111,23 +104,8 @@ protected slots:
|
|||
protected:
|
||||
virtual bool saveDownloadedData(const QByteArray &data);
|
||||
|
||||
void populateCache();
|
||||
|
||||
FollowRedirectReply* m_reply;
|
||||
|
||||
QVector<AdBlockRule*> m_rules;
|
||||
QVector<AdBlockRule*> m_createdRules;
|
||||
QString m_elementHidingRules;
|
||||
|
||||
QVector<const AdBlockRule*> m_networkExceptionRules;
|
||||
QVector<const AdBlockRule*> m_networkBlockRules;
|
||||
QVector<const AdBlockRule*> m_domainRestrictedCssRules;
|
||||
|
||||
QVector<const AdBlockRule*> m_documentRules;
|
||||
QVector<const AdBlockRule*> m_elemhideRules;
|
||||
|
||||
AdBlockSearchTree m_networkBlockTree;
|
||||
AdBlockSearchTree m_networkExceptionTree;
|
||||
|
||||
private:
|
||||
QString m_title;
|
||||
|
@ -155,9 +133,6 @@ public:
|
|||
int addRule(AdBlockRule* rule);
|
||||
bool removeRule(int offset);
|
||||
const AdBlockRule* replaceRule(AdBlockRule* rule, int offset);
|
||||
|
||||
signals:
|
||||
void subscriptionEdited();
|
||||
};
|
||||
|
||||
#endif // ADBLOCKSUBSCRIPTION_H
|
||||
|
|
|
@ -242,6 +242,7 @@ SOURCES += \
|
|||
webtab/searchtoolbar.cpp \
|
||||
webtab/tabbedwebview.cpp \
|
||||
webtab/webtab.cpp \
|
||||
adblock/adblockmatcher.cpp
|
||||
|
||||
HEADERS += \
|
||||
3rdparty/ecwin7.h \
|
||||
|
@ -445,6 +446,7 @@ HEADERS += \
|
|||
webtab/searchtoolbar.h \
|
||||
webtab/tabbedwebview.h \
|
||||
webtab/webtab.h \
|
||||
adblock/adblockmatcher.h
|
||||
|
||||
FORMS += \
|
||||
adblock/adblockaddsubscriptiondialog.ui \
|
||||
|
|
Loading…
Reference in New Issue
Block a user