1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-24 04: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);
}
else {
AdBlockRule rule(filter, customList);
AdBlockRule* rule = new AdBlockRule(filter, customList);
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
* 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
* 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:
AdBlockManager(QObject* parent = 0);
~AdBlockManager();
static AdBlockManager* instance();
void load();

View File

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

View File

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

View File

@ -118,10 +118,10 @@ void AdBlockSubscription::loadSubscription(const QStringList &disabledRules)
m_rules.clear();
while (!textStream.atEnd()) {
AdBlockRule rule(textStream.readLine(), this);
AdBlockRule* rule = new AdBlockRule(textStream.readLine(), this);
if (disabledRules.contains(rule.filter())) {
rule.setEnabled(false);
if (disabledRules.contains(rule->filter())) {
rule->setEnabled(false);
}
m_rules.append(rule);
@ -258,25 +258,25 @@ QString AdBlockSubscription::elementHidingRulesForDomain(const QString &domain)
const AdBlockRule* AdBlockSubscription::rule(int offset) const
{
if (!QzTools::listContainsIndex(m_rules, offset)) {
if (!QzTools::vectorContainsIndex(m_rules, offset)) {
return 0;
}
return &m_rules[offset];
return m_rules[offset];
}
QList<AdBlockRule> AdBlockSubscription::allRules() const
QVector<AdBlockRule*> AdBlockSubscription::allRules() const
{
return m_rules;
}
const AdBlockRule* AdBlockSubscription::enableRule(int offset)
{
if (!QzTools::listContainsIndex(m_rules, offset)) {
if (!QzTools::vectorContainsIndex(m_rules, offset)) {
return 0;
}
AdBlockRule* rule = &m_rules[offset];
AdBlockRule* rule = m_rules[offset];
rule->setEnabled(true);
AdBlockManager::instance()->removeDisabledRule(rule->filter());
@ -290,11 +290,11 @@ const AdBlockRule* AdBlockSubscription::enableRule(int offset)
const AdBlockRule* AdBlockSubscription::disableRule(int offset)
{
if (!QzTools::listContainsIndex(m_rules, offset)) {
if (!QzTools::vectorContainsIndex(m_rules, offset)) {
return 0;
}
AdBlockRule* rule = &m_rules[offset];
AdBlockRule* rule = m_rules[offset];
rule->setEnabled(false);
AdBlockManager::instance()->addDisabledRule(rule->filter());
@ -316,7 +316,7 @@ bool AdBlockSubscription::canBeRemoved() const
return true;
}
int AdBlockSubscription::addRule(const AdBlockRule &rule)
int AdBlockSubscription::addRule(AdBlockRule* rule)
{
Q_UNUSED(rule)
return -1;
@ -328,7 +328,7 @@ bool AdBlockSubscription::removeRule(int offset)
return false;
}
const AdBlockRule* AdBlockSubscription::replaceRule(const AdBlockRule &rule, int offset)
const AdBlockRule* AdBlockSubscription::replaceRule(AdBlockRule* rule, int offset)
{
Q_UNUSED(rule)
Q_UNUSED(offset)
@ -346,7 +346,7 @@ void AdBlockSubscription::populateCache()
int count = m_rules.count();
for (int i = 0; i < count; ++i) {
const AdBlockRule* rule = &m_rules.at(i);
const AdBlockRule* rule = m_rules.at(i);
if (!rule->isEnabled()) {
continue;
}
@ -428,8 +428,8 @@ void AdBlockCustomList::saveSubscription()
textStream << "Url: " << url().toString() << endl;
textStream << "[Adblock Plus 1.1.1]" << endl;
foreach(const AdBlockRule & rule, m_rules) {
textStream << rule.filter() << endl;
foreach(const AdBlockRule * rule, m_rules) {
textStream << rule->filter() << endl;
}
file.close();
@ -447,8 +447,8 @@ bool AdBlockCustomList::canBeRemoved() const
bool AdBlockCustomList::containsFilter(const QString &filter) const
{
foreach(const AdBlockRule & rule, m_rules) {
if (rule.filter() == filter) {
foreach(const AdBlockRule * rule, m_rules) {
if (rule->filter() == filter) {
return true;
}
}
@ -459,9 +459,9 @@ bool AdBlockCustomList::containsFilter(const QString &filter) const
bool AdBlockCustomList::removeFilter(const QString &filter)
{
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);
}
}
@ -469,7 +469,7 @@ bool AdBlockCustomList::removeFilter(const QString &filter)
return false;
}
int AdBlockCustomList::addRule(const AdBlockRule &rule)
int AdBlockCustomList::addRule(AdBlockRule* rule)
{
m_rules.append(rule);
populateCache();
@ -481,32 +481,41 @@ int AdBlockCustomList::addRule(const AdBlockRule &rule)
bool AdBlockCustomList::removeRule(int offset)
{
if (!QzTools::listContainsIndex(m_rules, offset)) {
if (!QzTools::vectorContainsIndex(m_rules, offset)) {
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();
emit subscriptionEdited();
AdBlockManager::instance()->removeDisabledRule(filter);
delete rule;
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;
}
delete m_rules.at(offset);
m_rules[offset] = rule;
populateCache();
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
* 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
* it under the terms of the GNU General Public License as published by
@ -46,8 +46,7 @@
#ifndef ADBLOCKSUBSCRIPTION_H
#define ADBLOCKSUBSCRIPTION_H
#include <QVarLengthArray>
#include <QList>
#include <QVector>
#include <QUrl>
#include "qz_namespace.h"
@ -64,6 +63,7 @@ class QT_QUPZILLA_EXPORT AdBlockSubscription : public QObject
Q_OBJECT
public:
explicit AdBlockSubscription(const QString &title, QObject* parent = 0);
~AdBlockSubscription();
QString title() const;
@ -85,7 +85,7 @@ public:
QString elementHidingRulesForDomain(const QString &domain) const;
const AdBlockRule* rule(int offset) const;
QList<AdBlockRule> allRules() const;
QVector<AdBlockRule*> allRules() const;
const AdBlockRule* enableRule(int offset);
const AdBlockRule* disableRule(int offset);
@ -93,9 +93,9 @@ public:
virtual bool canEditRules() const;
virtual bool canBeRemoved() const;
virtual int addRule(const AdBlockRule &rule);
virtual int addRule(AdBlockRule* rule);
virtual bool removeRule(int offset);
virtual const AdBlockRule* replaceRule(const AdBlockRule &rule, int offset);
virtual const AdBlockRule* replaceRule(AdBlockRule* rule, int offset);
public slots:
void updateSubscription();
@ -113,15 +113,15 @@ protected:
FollowRedirectReply* m_reply;
QList<AdBlockRule> m_rules;
QVector<AdBlockRule*> m_rules;
QString m_elementHidingRules;
QVarLengthArray<const AdBlockRule*> m_networkExceptionRules;
QVarLengthArray<const AdBlockRule*> m_networkBlockRules;
QVarLengthArray<const AdBlockRule*> m_domainRestrictedCssRules;
QVector<const AdBlockRule*> m_networkExceptionRules;
QVector<const AdBlockRule*> m_networkBlockRules;
QVector<const AdBlockRule*> m_domainRestrictedCssRules;
QVarLengthArray<const AdBlockRule*> m_documentRules;
QVarLengthArray<const AdBlockRule*> m_elemhideRules;
QVector<const AdBlockRule*> m_documentRules;
QVector<const AdBlockRule*> m_elemhideRules;
private:
QString m_title;
@ -157,9 +157,9 @@ public:
bool containsFilter(const QString &filter) const;
bool removeFilter(const QString &filter);
int addRule(const AdBlockRule &rule);
int addRule(AdBlockRule* rule);
bool removeRule(int offset);
const AdBlockRule* replaceRule(const AdBlockRule &rule, int offset);
const AdBlockRule* replaceRule(AdBlockRule* rule, int offset);
signals:
void subscriptionEdited();

View File

@ -1,6 +1,6 @@
/* ============================================================
* 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
* it under the terms of the GNU General Public License as published by
@ -101,19 +101,20 @@ void AdBlockTreeWidget::itemChanged(QTreeWidgetItem* item)
// Disable rule
const AdBlockRule* rule = m_subscription->disableRule(offset);
adjustItemFeatures(item, *rule);
adjustItemFeatures(item, rule);
}
else if (item->checkState(0) == Qt::Checked && !oldRule->isEnabled()) {
// Enable rule
const AdBlockRule* rule = m_subscription->enableRule(offset);
adjustItemFeatures(item, *rule);
adjustItemFeatures(item, rule);
}
else if (m_subscription->canEditRules()) {
// 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;
@ -140,7 +141,7 @@ void AdBlockTreeWidget::addRule()
return;
}
AdBlockRule rule(newRule, m_subscription);
AdBlockRule* rule = new AdBlockRule(newRule, m_subscription);
int offset = m_subscription->addRule(rule);
QTreeWidgetItem* item = new QTreeWidgetItem();
@ -177,14 +178,14 @@ void AdBlockTreeWidget::subscriptionUpdated()
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;
font.setItalic(true);
item->setForeground(0, QColor(Qt::gray));
if (!rule.isComment()) {
if (!rule->isComment()) {
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(0, Qt::Unchecked);
item->setFont(0, font);
@ -196,11 +197,11 @@ void AdBlockTreeWidget::adjustItemFeatures(QTreeWidgetItem* item, const AdBlockR
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(0, Qt::Checked);
if (rule.isCssRule()) {
if (rule->isCssRule()) {
item->setForeground(0, QColor(Qt::darkBlue));
item->setFont(0, QFont());
}
else if (rule.isException()) {
else if (rule->isException()) {
item->setForeground(0, QColor(Qt::darkGreen));
item->setFont(0, QFont());
}
@ -236,12 +237,12 @@ void AdBlockTreeWidget::refresh()
m_topItem->setFont(0, boldFont);
addTopLevelItem(m_topItem);
const QList<AdBlockRule> &allRules = m_subscription->allRules();
const QVector<AdBlockRule*> &allRules = m_subscription->allRules();
int index = 0;
foreach(const AdBlockRule & rule, allRules) {
foreach(const AdBlockRule * rule, allRules) {
QTreeWidgetItem* item = new QTreeWidgetItem(m_topItem);
item->setText(0, rule.filter());
item->setText(0, rule->filter());
item->setData(0, Qt::UserRole + 10, index);
if (m_subscription->canEditRules()) {

View File

@ -1,6 +1,6 @@
/* ============================================================
* 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
* it under the terms of the GNU General Public License as published by
@ -49,7 +49,7 @@ private slots:
void subscriptionUpdated();
private:
void adjustItemFeatures(QTreeWidgetItem* item, const AdBlockRule &rule);
void adjustItemFeatures(QTreeWidgetItem* item, const AdBlockRule* rule);
void keyPressEvent(QKeyEvent* event);
AdBlockSubscription* m_subscription;

View File

@ -79,6 +79,12 @@ bool listContainsIndex(const QList<T> &list, int 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
#endif // GLOBALFUNCTIONS_H