1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-20 02:36:34 +01:00

Significant memory savings in AdBlock (~ 30MB with just EasyList)

Even empty QRegExp can occupy a lot of space in memory, which can
grow into a big number with tens of thousands AdBlock rules.
QRegExp is now allocated with new, and only when really needed.
This commit is contained in:
nowrep 2013-02-26 10:42:48 +01:00
parent a1ad8dab9b
commit 9f226b9738
10 changed files with 94 additions and 69 deletions

View File

@ -184,7 +184,7 @@ void AdBlockIcon::toggleCustomFilter()
customList->removeFilter(filter); customList->removeFilter(filter);
} }
else { else {
AdBlockRule rule(filter, customList); AdBlockRule* rule = new AdBlockRule(filter, customList);
customList->addRule(rule); customList->addRule(rule);
} }
} }

View File

@ -375,3 +375,8 @@ void AdBlockManager::showRule()
} }
} }
} }
AdBlockManager::~AdBlockManager()
{
qDeleteAll(m_subscriptions);
}

View File

@ -1,6 +1,6 @@
/* ============================================================ /* ============================================================
* QupZilla - WebKit based browser * QupZilla - WebKit based browser
* Copyright (C) 2010-2012 David Rosca <nowrep@gmail.com> * Copyright (C) 2010-2013 David Rosca <nowrep@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -38,6 +38,8 @@ class QT_QUPZILLA_EXPORT AdBlockManager : public QObject
public: public:
AdBlockManager(QObject* parent = 0); AdBlockManager(QObject* parent = 0);
~AdBlockManager();
static AdBlockManager* instance(); static AdBlockManager* instance();
void load(); void load();

View File

@ -101,7 +101,7 @@ AdBlockRule::AdBlockRule(const QString &filter, AdBlockSubscription* subscriptio
, m_exception(false) , m_exception(false)
, m_internalDisabled(false) , m_internalDisabled(false)
, m_domainRestricted(false) , m_domainRestricted(false)
, m_useRegExp(false) , m_regExp(0)
, m_useDomainMatch(false) , m_useDomainMatch(false)
, m_useEndsMatch(false) , m_useEndsMatch(false)
, m_thirdParty(false) , m_thirdParty(false)
@ -189,7 +189,7 @@ void AdBlockRule::setEnabled(bool enabled)
bool AdBlockRule::isSlow() const bool AdBlockRule::isSlow() const
{ {
return m_useRegExp; return m_regExp != 0;
} }
bool AdBlockRule::isInternalDisabled() const bool AdBlockRule::isInternalDisabled() const
@ -211,8 +211,8 @@ bool AdBlockRule::networkMatch(const QNetworkRequest &request, const QString &do
else if (m_useEndsMatch) { else if (m_useEndsMatch) {
matched = encodedUrl.endsWith(m_matchString, m_caseSensitivity); matched = encodedUrl.endsWith(m_matchString, m_caseSensitivity);
} }
else if (m_useRegExp) { else if (m_regExp) {
matched = (m_regExp.indexIn(encodedUrl) != -1); matched = (m_regExp->indexIn(encodedUrl) != -1);
} }
else { else {
matched = encodedUrl.contains(m_matchString, m_caseSensitivity); matched = encodedUrl.contains(m_matchString, m_caseSensitivity);
@ -466,8 +466,7 @@ void AdBlockRule::parseFilter()
parsedLine = parsedLine.mid(1); parsedLine = parsedLine.mid(1);
parsedLine = parsedLine.left(parsedLine.size() - 1); parsedLine = parsedLine.left(parsedLine.size() - 1);
m_useRegExp = true; m_regExp = new QzRegExp(parsedLine, m_caseSensitivity);
m_regExp = QzRegExp(parsedLine, m_caseSensitivity);
return; return;
} }
@ -518,13 +517,11 @@ void AdBlockRule::parseFilter()
.replace(QzRegExp(QLatin1String("\\\\\\|$")), QLatin1String("$")) // process anchor at expression end .replace(QzRegExp(QLatin1String("\\\\\\|$")), QLatin1String("$")) // process anchor at expression end
.replace(QzRegExp(QLatin1String("\\\\\\*")), QLatin1String(".*")); // replace wildcards by .* .replace(QzRegExp(QLatin1String("\\\\\\*")), QLatin1String(".*")); // replace wildcards by .*
m_useRegExp = true; m_regExp = new QzRegExp(parsedLine, m_caseSensitivity);
m_regExp = QzRegExp(parsedLine, m_caseSensitivity);
return; return;
} }
// We haven't found anything that needs use of regexp, yay! // We haven't found anything that needs use of regexp, yay!
m_useRegExp = false;
m_matchString = parsedLine; m_matchString = parsedLine;
} }
@ -561,3 +558,8 @@ bool AdBlockRule::_matchDomain(const QString &domain, const QString &filter) con
return domain[index - 1] == QLatin1Char('.'); return domain[index - 1] == QLatin1Char('.');
} }
AdBlockRule::~AdBlockRule()
{
delete m_regExp;
}

View File

@ -61,6 +61,7 @@ class AdBlockRule
{ {
public: public:
AdBlockRule(const QString &filter = QString(), AdBlockSubscription* subscription = 0); AdBlockRule(const QString &filter = QString(), AdBlockSubscription* subscription = 0);
~AdBlockRule();
AdBlockSubscription* subscription() const; AdBlockSubscription* subscription() const;
void setSubscription(AdBlockSubscription* subscription); void setSubscription(AdBlockSubscription* subscription);
@ -110,8 +111,7 @@ private:
bool m_internalDisabled; bool m_internalDisabled;
bool m_domainRestricted; bool m_domainRestricted;
bool m_useRegExp; QzRegExp* m_regExp;
QzRegExp m_regExp;
bool m_useDomainMatch; bool m_useDomainMatch;
bool m_useEndsMatch; bool m_useEndsMatch;

View File

@ -118,10 +118,10 @@ void AdBlockSubscription::loadSubscription(const QStringList &disabledRules)
m_rules.clear(); m_rules.clear();
while (!textStream.atEnd()) { while (!textStream.atEnd()) {
AdBlockRule rule(textStream.readLine(), this); AdBlockRule* rule = new AdBlockRule(textStream.readLine(), this);
if (disabledRules.contains(rule.filter())) { if (disabledRules.contains(rule->filter())) {
rule.setEnabled(false); rule->setEnabled(false);
} }
m_rules.append(rule); m_rules.append(rule);
@ -258,25 +258,25 @@ QString AdBlockSubscription::elementHidingRulesForDomain(const QString &domain)
const AdBlockRule* AdBlockSubscription::rule(int offset) const const AdBlockRule* AdBlockSubscription::rule(int offset) const
{ {
if (!QzTools::listContainsIndex(m_rules, offset)) { if (!QzTools::vectorContainsIndex(m_rules, offset)) {
return 0; return 0;
} }
return &m_rules[offset]; return m_rules[offset];
} }
QList<AdBlockRule> AdBlockSubscription::allRules() const QVector<AdBlockRule*> AdBlockSubscription::allRules() const
{ {
return m_rules; return m_rules;
} }
const AdBlockRule* AdBlockSubscription::enableRule(int offset) const AdBlockRule* AdBlockSubscription::enableRule(int offset)
{ {
if (!QzTools::listContainsIndex(m_rules, offset)) { if (!QzTools::vectorContainsIndex(m_rules, offset)) {
return 0; return 0;
} }
AdBlockRule* rule = &m_rules[offset]; AdBlockRule* rule = m_rules[offset];
rule->setEnabled(true); rule->setEnabled(true);
AdBlockManager::instance()->removeDisabledRule(rule->filter()); AdBlockManager::instance()->removeDisabledRule(rule->filter());
@ -290,11 +290,11 @@ const AdBlockRule* AdBlockSubscription::enableRule(int offset)
const AdBlockRule* AdBlockSubscription::disableRule(int offset) const AdBlockRule* AdBlockSubscription::disableRule(int offset)
{ {
if (!QzTools::listContainsIndex(m_rules, offset)) { if (!QzTools::vectorContainsIndex(m_rules, offset)) {
return 0; return 0;
} }
AdBlockRule* rule = &m_rules[offset]; AdBlockRule* rule = m_rules[offset];
rule->setEnabled(false); rule->setEnabled(false);
AdBlockManager::instance()->addDisabledRule(rule->filter()); AdBlockManager::instance()->addDisabledRule(rule->filter());
@ -316,7 +316,7 @@ bool AdBlockSubscription::canBeRemoved() const
return true; return true;
} }
int AdBlockSubscription::addRule(const AdBlockRule &rule) int AdBlockSubscription::addRule(AdBlockRule* rule)
{ {
Q_UNUSED(rule) Q_UNUSED(rule)
return -1; return -1;
@ -328,7 +328,7 @@ bool AdBlockSubscription::removeRule(int offset)
return false; return false;
} }
const AdBlockRule* AdBlockSubscription::replaceRule(const AdBlockRule &rule, int offset) const AdBlockRule* AdBlockSubscription::replaceRule(AdBlockRule* rule, int offset)
{ {
Q_UNUSED(rule) Q_UNUSED(rule)
Q_UNUSED(offset) Q_UNUSED(offset)
@ -346,7 +346,7 @@ void AdBlockSubscription::populateCache()
int count = m_rules.count(); int count = m_rules.count();
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
const AdBlockRule* rule = &m_rules.at(i); const AdBlockRule* rule = m_rules.at(i);
if (!rule->isEnabled()) { if (!rule->isEnabled()) {
continue; continue;
} }
@ -428,8 +428,8 @@ void AdBlockCustomList::saveSubscription()
textStream << "Url: " << url().toString() << endl; textStream << "Url: " << url().toString() << endl;
textStream << "[Adblock Plus 1.1.1]" << endl; textStream << "[Adblock Plus 1.1.1]" << endl;
foreach(const AdBlockRule & rule, m_rules) { foreach(const AdBlockRule * rule, m_rules) {
textStream << rule.filter() << endl; textStream << rule->filter() << endl;
} }
file.close(); file.close();
@ -447,8 +447,8 @@ bool AdBlockCustomList::canBeRemoved() const
bool AdBlockCustomList::containsFilter(const QString &filter) const bool AdBlockCustomList::containsFilter(const QString &filter) const
{ {
foreach(const AdBlockRule & rule, m_rules) { foreach(const AdBlockRule * rule, m_rules) {
if (rule.filter() == filter) { if (rule->filter() == filter) {
return true; return true;
} }
} }
@ -459,9 +459,9 @@ bool AdBlockCustomList::containsFilter(const QString &filter) const
bool AdBlockCustomList::removeFilter(const QString &filter) bool AdBlockCustomList::removeFilter(const QString &filter)
{ {
for (int i = 0; i < m_rules.count(); ++i) { for (int i = 0; i < m_rules.count(); ++i) {
const AdBlockRule rule = m_rules.at(i); const AdBlockRule* rule = m_rules.at(i);
if (rule.filter() == filter) { if (rule->filter() == filter) {
return removeRule(i); return removeRule(i);
} }
} }
@ -469,7 +469,7 @@ bool AdBlockCustomList::removeFilter(const QString &filter)
return false; return false;
} }
int AdBlockCustomList::addRule(const AdBlockRule &rule) int AdBlockCustomList::addRule(AdBlockRule* rule)
{ {
m_rules.append(rule); m_rules.append(rule);
populateCache(); populateCache();
@ -481,32 +481,41 @@ int AdBlockCustomList::addRule(const AdBlockRule &rule)
bool AdBlockCustomList::removeRule(int offset) bool AdBlockCustomList::removeRule(int offset)
{ {
if (!QzTools::listContainsIndex(m_rules, offset)) { if (!QzTools::vectorContainsIndex(m_rules, offset)) {
return false; return false;
} }
const QString &filter = m_rules[offset].filter(); AdBlockRule* rule = m_rules.at(offset);
const QString &filter = rule->filter();
m_rules.removeAt(offset); m_rules.remove(offset);
populateCache(); populateCache();
emit subscriptionEdited(); emit subscriptionEdited();
AdBlockManager::instance()->removeDisabledRule(filter); AdBlockManager::instance()->removeDisabledRule(filter);
delete rule;
return true; return true;
} }
const AdBlockRule* AdBlockCustomList::replaceRule(const AdBlockRule &rule, int offset) const AdBlockRule* AdBlockCustomList::replaceRule(AdBlockRule* rule, int offset)
{ {
if (!QzTools::listContainsIndex(m_rules, offset)) { if (!QzTools::vectorContainsIndex(m_rules, offset)) {
return 0; return 0;
} }
delete m_rules.at(offset);
m_rules[offset] = rule; m_rules[offset] = rule;
populateCache(); populateCache();
emit subscriptionEdited(); emit subscriptionEdited();
return &m_rules[offset]; return m_rules[offset];
}
AdBlockSubscription::~AdBlockSubscription()
{
qDeleteAll(m_rules);
} }

View File

@ -1,6 +1,6 @@
/* ============================================================ /* ============================================================
* QupZilla - WebKit based browser * QupZilla - WebKit based browser
* Copyright (C) 2010-2012 David Rosca <nowrep@gmail.com> * Copyright (C) 2010-2013 David Rosca <nowrep@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -46,8 +46,7 @@
#ifndef ADBLOCKSUBSCRIPTION_H #ifndef ADBLOCKSUBSCRIPTION_H
#define ADBLOCKSUBSCRIPTION_H #define ADBLOCKSUBSCRIPTION_H
#include <QVarLengthArray> #include <QVector>
#include <QList>
#include <QUrl> #include <QUrl>
#include "qz_namespace.h" #include "qz_namespace.h"
@ -64,6 +63,7 @@ class QT_QUPZILLA_EXPORT AdBlockSubscription : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit AdBlockSubscription(const QString &title, QObject* parent = 0); explicit AdBlockSubscription(const QString &title, QObject* parent = 0);
~AdBlockSubscription();
QString title() const; QString title() const;
@ -85,7 +85,7 @@ public:
QString elementHidingRulesForDomain(const QString &domain) const; QString elementHidingRulesForDomain(const QString &domain) const;
const AdBlockRule* rule(int offset) const; const AdBlockRule* rule(int offset) const;
QList<AdBlockRule> allRules() const; QVector<AdBlockRule*> allRules() const;
const AdBlockRule* enableRule(int offset); const AdBlockRule* enableRule(int offset);
const AdBlockRule* disableRule(int offset); const AdBlockRule* disableRule(int offset);
@ -93,9 +93,9 @@ public:
virtual bool canEditRules() const; virtual bool canEditRules() const;
virtual bool canBeRemoved() const; virtual bool canBeRemoved() const;
virtual int addRule(const AdBlockRule &rule); virtual int addRule(AdBlockRule* rule);
virtual bool removeRule(int offset); virtual bool removeRule(int offset);
virtual const AdBlockRule* replaceRule(const AdBlockRule &rule, int offset); virtual const AdBlockRule* replaceRule(AdBlockRule* rule, int offset);
public slots: public slots:
void updateSubscription(); void updateSubscription();
@ -113,15 +113,15 @@ protected:
FollowRedirectReply* m_reply; FollowRedirectReply* m_reply;
QList<AdBlockRule> m_rules; QVector<AdBlockRule*> m_rules;
QString m_elementHidingRules; QString m_elementHidingRules;
QVarLengthArray<const AdBlockRule*> m_networkExceptionRules; QVector<const AdBlockRule*> m_networkExceptionRules;
QVarLengthArray<const AdBlockRule*> m_networkBlockRules; QVector<const AdBlockRule*> m_networkBlockRules;
QVarLengthArray<const AdBlockRule*> m_domainRestrictedCssRules; QVector<const AdBlockRule*> m_domainRestrictedCssRules;
QVarLengthArray<const AdBlockRule*> m_documentRules; QVector<const AdBlockRule*> m_documentRules;
QVarLengthArray<const AdBlockRule*> m_elemhideRules; QVector<const AdBlockRule*> m_elemhideRules;
private: private:
QString m_title; QString m_title;
@ -157,9 +157,9 @@ public:
bool containsFilter(const QString &filter) const; bool containsFilter(const QString &filter) const;
bool removeFilter(const QString &filter); bool removeFilter(const QString &filter);
int addRule(const AdBlockRule &rule); int addRule(AdBlockRule* rule);
bool removeRule(int offset); bool removeRule(int offset);
const AdBlockRule* replaceRule(const AdBlockRule &rule, int offset); const AdBlockRule* replaceRule(AdBlockRule* rule, int offset);
signals: signals:
void subscriptionEdited(); void subscriptionEdited();

View File

@ -1,6 +1,6 @@
/* ============================================================ /* ============================================================
* QupZilla - WebKit based browser * QupZilla - WebKit based browser
* Copyright (C) 2010-2012 David Rosca <nowrep@gmail.com> * Copyright (C) 2010-2013 David Rosca <nowrep@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -101,19 +101,20 @@ void AdBlockTreeWidget::itemChanged(QTreeWidgetItem* item)
// Disable rule // Disable rule
const AdBlockRule* rule = m_subscription->disableRule(offset); const AdBlockRule* rule = m_subscription->disableRule(offset);
adjustItemFeatures(item, *rule); adjustItemFeatures(item, rule);
} }
else if (item->checkState(0) == Qt::Checked && !oldRule->isEnabled()) { else if (item->checkState(0) == Qt::Checked && !oldRule->isEnabled()) {
// Enable rule // Enable rule
const AdBlockRule* rule = m_subscription->enableRule(offset); const AdBlockRule* rule = m_subscription->enableRule(offset);
adjustItemFeatures(item, *rule); adjustItemFeatures(item, rule);
} }
else if (m_subscription->canEditRules()) { else if (m_subscription->canEditRules()) {
// Custom rule has been changed // Custom rule has been changed
const AdBlockRule* rule = m_subscription->replaceRule(AdBlockRule(item->text(0), m_subscription), offset); AdBlockRule* newRule = new AdBlockRule(item->text(0), m_subscription);
const AdBlockRule* rule = m_subscription->replaceRule(newRule, offset);
adjustItemFeatures(item, *rule); adjustItemFeatures(item, rule);
} }
m_itemChangingBlock = false; m_itemChangingBlock = false;
@ -140,7 +141,7 @@ void AdBlockTreeWidget::addRule()
return; return;
} }
AdBlockRule rule(newRule, m_subscription); AdBlockRule* rule = new AdBlockRule(newRule, m_subscription);
int offset = m_subscription->addRule(rule); int offset = m_subscription->addRule(rule);
QTreeWidgetItem* item = new QTreeWidgetItem(); QTreeWidgetItem* item = new QTreeWidgetItem();
@ -177,14 +178,14 @@ void AdBlockTreeWidget::subscriptionUpdated()
m_itemChangingBlock = false; m_itemChangingBlock = false;
} }
void AdBlockTreeWidget::adjustItemFeatures(QTreeWidgetItem* item, const AdBlockRule &rule) void AdBlockTreeWidget::adjustItemFeatures(QTreeWidgetItem* item, const AdBlockRule* rule)
{ {
if (!rule.isEnabled()) { if (!rule->isEnabled()) {
QFont font; QFont font;
font.setItalic(true); font.setItalic(true);
item->setForeground(0, QColor(Qt::gray)); item->setForeground(0, QColor(Qt::gray));
if (!rule.isComment()) { if (!rule->isComment()) {
item->setFlags(item->flags() | Qt::ItemIsUserCheckable); item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(0, Qt::Unchecked); item->setCheckState(0, Qt::Unchecked);
item->setFont(0, font); item->setFont(0, font);
@ -196,11 +197,11 @@ void AdBlockTreeWidget::adjustItemFeatures(QTreeWidgetItem* item, const AdBlockR
item->setFlags(item->flags() | Qt::ItemIsUserCheckable); item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(0, Qt::Checked); item->setCheckState(0, Qt::Checked);
if (rule.isCssRule()) { if (rule->isCssRule()) {
item->setForeground(0, QColor(Qt::darkBlue)); item->setForeground(0, QColor(Qt::darkBlue));
item->setFont(0, QFont()); item->setFont(0, QFont());
} }
else if (rule.isException()) { else if (rule->isException()) {
item->setForeground(0, QColor(Qt::darkGreen)); item->setForeground(0, QColor(Qt::darkGreen));
item->setFont(0, QFont()); item->setFont(0, QFont());
} }
@ -236,12 +237,12 @@ void AdBlockTreeWidget::refresh()
m_topItem->setFont(0, boldFont); m_topItem->setFont(0, boldFont);
addTopLevelItem(m_topItem); addTopLevelItem(m_topItem);
const QList<AdBlockRule> &allRules = m_subscription->allRules(); const QVector<AdBlockRule*> &allRules = m_subscription->allRules();
int index = 0; int index = 0;
foreach(const AdBlockRule & rule, allRules) { foreach(const AdBlockRule * rule, allRules) {
QTreeWidgetItem* item = new QTreeWidgetItem(m_topItem); QTreeWidgetItem* item = new QTreeWidgetItem(m_topItem);
item->setText(0, rule.filter()); item->setText(0, rule->filter());
item->setData(0, Qt::UserRole + 10, index); item->setData(0, Qt::UserRole + 10, index);
if (m_subscription->canEditRules()) { if (m_subscription->canEditRules()) {

View File

@ -1,6 +1,6 @@
/* ============================================================ /* ============================================================
* QupZilla - WebKit based browser * QupZilla - WebKit based browser
* Copyright (C) 2010-2012 David Rosca <nowrep@gmail.com> * Copyright (C) 2010-2013 David Rosca <nowrep@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -49,7 +49,7 @@ private slots:
void subscriptionUpdated(); void subscriptionUpdated();
private: private:
void adjustItemFeatures(QTreeWidgetItem* item, const AdBlockRule &rule); void adjustItemFeatures(QTreeWidgetItem* item, const AdBlockRule* rule);
void keyPressEvent(QKeyEvent* event); void keyPressEvent(QKeyEvent* event);
AdBlockSubscription* m_subscription; AdBlockSubscription* m_subscription;

View File

@ -79,6 +79,12 @@ bool listContainsIndex(const QList<T> &list, int index)
return (index >= 0 && list.count() > index); return (index >= 0 && list.count() > index);
} }
template <typename T>
bool vectorContainsIndex(const QVector<T> &list, int index)
{
return (index >= 0 && list.count() > index);
}
} // namespace } // namespace
#endif // GLOBALFUNCTIONS_H #endif // GLOBALFUNCTIONS_H