| Index: compiled/ElemHide.cpp |
| =================================================================== |
| new file mode 100644 |
| --- /dev/null |
| +++ b/compiled/ElemHide.cpp |
| @@ -0,0 +1,238 @@ |
| +/* |
| + * This file is part of Adblock Plus <https://adblockplus.org/>, |
| + * Copyright (C) 2006-present eyeo GmbH |
| + * |
| + * Adblock Plus is free software: you can redistribute it and/or modify |
| + * it under the terms of the GNU General Public License version 3 as |
| + * published by the Free Software Foundation. |
| + * |
| + * Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| + */ |
| + |
| +#include "ElemHide.h" |
| + |
| +DependentString _ElemHide_SelectorList::SelectorAt(size_t idx) const |
| +{ |
| + return DependentString(mSelectors[idx]->GetSelector()); |
| +} |
| + |
| +const String& _ElemHide_SelectorList::FilterKeyAt(size_t idx) const |
| +{ |
| + return mSelectors[idx]->GetText(); |
| +} |
| + |
| +ElemHide* ElemHide::mInstance = new ElemHide(); |
| + |
| +void ElemHide::Clear() |
| +{ |
| + mFilters.clear(); |
| + mExceptions.clear(); |
| + mFiltersByDomain.clear(); |
| + mKnownExceptions.clear(); |
| +} |
| + |
| +namespace { |
| + |
| + ActiveFilter::DomainMap* DefaultDomains() |
| + { |
| + static ActiveFilter::DomainMap defaultDomains; |
| + if (defaultDomains.empty()) |
| + defaultDomains[u""_str] = true; |
| + return &defaultDomains; |
| + } |
| + |
| +} |
| + |
| +void ElemHide::AddToFiltersByDomain(ElemHideBase& filter) |
| +{ |
| + auto domains = filter.GetDomains(); |
| + if (!domains) |
| + domains = DefaultDomains(); |
| + |
| + DependentString text(filter.GetText()); |
| + for (auto& domain : *domains) |
| + { |
| + auto& filters = mFiltersByDomain[domain.first]; |
| + if (domain.second) |
| + filters[text] = ElemHideBasePtr(&filter); |
| + else |
| + { |
| + auto iter = filters.find(text); |
| + if (iter != filters.end()) |
| + filters.erase(iter); |
| + } |
| + } |
| +} |
| + |
| +void ElemHide::Add(ElemHideBase& filter) |
| +{ |
| + // we must ensure we have the right class. |
| + // This is an error, but we might get Invalid filters. |
| + if (!filter.As<ElemHideBase>()) |
| + return; |
| + |
| + DependentString text(filter.GetText()); |
| + if (filter.mType == Filter::Type::ELEMHIDEEXCEPTION) |
| + { |
| + if (mKnownExceptions.find(text)) |
| + return; |
| + |
| + auto selector = filter.GetSelector(); |
| + mExceptions[selector].push_back( |
| + ElemHideExceptionPtr(filter.As<ElemHideException>())); |
| + |
| + // Selector is not longer unconditional |
| + mUnconditionalSelectors.erase(text); |
| + mUnconditionalSelectorsCache.reset(); |
| + mKnownExceptions.insert(text); |
| + } |
| + else |
| + { |
| + if (mFilters.find(text)) |
| + return; |
| + |
| + mFilters[text] = ElemHideBasePtr(filter.As<ElemHideBase>()); |
| + if (!((filter.GetDomains() && filter.GetDomains()->size()) || |
| + mExceptions.find(filter.GetSelector()))) |
| + { |
| + // The new filter's selector is unconditionally applied to all domains |
| + mUnconditionalSelectors.insert(text); |
| + mUnconditionalSelectorsCache.reset(); |
| + } |
| + else |
| + { |
| + AddToFiltersByDomain(filter); |
| + } |
| + } |
| +} |
| + |
| +void ElemHide::Remove(ElemHideBase& filter) |
| +{ |
| + DependentString text(filter.GetText()); |
| + |
| + if (filter.mType == Filter::Type::ELEMHIDEEXCEPTION) |
| + { |
| + // never seen the exception. |
| + if (!mKnownExceptions.find(text)) |
| + return; |
| + |
| + auto selector = filter.GetSelector(); |
| + auto& list = mExceptions[selector]; |
| + auto iter = std::find( |
| + list.begin(), list.end(), |
| + ElemHideExceptionPtr(filter.As<ElemHideException>())); |
| + if (iter != list.end()) |
| + list.erase(iter); |
| + mKnownExceptions.erase(text); |
| + } |
| + else |
| + { |
| + if (!mFilters.find(text)) |
| + return; |
| + |
| + if (mUnconditionalSelectors.find(text)) |
| + { |
| + mUnconditionalSelectors.erase(text); |
| + mUnconditionalSelectorsCache.reset(); |
| + } |
| + else |
| + { |
| + auto domains = filter.GetDomains(); |
| + for (auto domain : *domains) |
| + { |
| + auto& list = mFiltersByDomain[domain.first]; |
| + list.erase(text); |
| + } |
| + } |
| + |
| + mFilters.erase(text); |
| + } |
| +} |
| + |
| +ElemHideException* ElemHide::GetException(const ElemHideBase& filter, |
| + DependentString& docDomain) const |
| +{ |
| + auto exception = mExceptions.find(filter.GetSelector()); |
| + if (!exception) |
| + return nullptr; |
| + |
| + auto& list = exception->second; |
| + for (auto iter = list.rbegin(); iter != list.rend(); iter++) |
| + if ((*iter)->IsActiveOnDomain(docDomain, u""_str)) |
| + { |
| + ElemHideExceptionPtr filter(*iter); |
| + return filter.release(); |
| + } |
| + |
| + return nullptr; |
| +} |
| + |
| +_ElemHide_SelectorList* ElemHide::GetUnconditionalSelectors() const |
| +{ |
| + if (!mUnconditionalSelectorsCache) |
| + { |
| + mUnconditionalSelectorsCache = intrusive_ptr<_ElemHide_SelectorList>(new _ElemHide_SelectorList, false); |
| + annotate_address(mUnconditionalSelectorsCache.get(), "_ElemHide_SelectorList"); |
| + for (auto unconditional : mUnconditionalSelectors) |
| + { |
| + auto filter = mFilters.find(unconditional.first); |
| + if (filter) |
| + mUnconditionalSelectorsCache->push_back(filter->second); |
| + } |
| + } |
| + return mUnconditionalSelectorsCache.get(); |
| +} |
| + |
| +_ElemHide_SelectorList* ElemHide::GetSelectorsForDomain(const String& domain, |
| + Criteria criteria) const |
| +{ |
| + _ElemHide_SelectorList* selectors = new _ElemHide_SelectorList; |
| + annotate_address(selectors, "_ElemHide_SelectorList"); |
| + |
| + if (criteria < NO_UNCONDITIONAL) |
| + selectors->append(GetUnconditionalSelectors()); |
| + |
| + bool specificOnly = (criteria >= SPECIFIC_ONLY); |
| + StringSet seenFilters; |
| + DependentString docDomain(domain); |
| + |
| + DependentString currentDomain(domain); |
| + while (true) |
| + { |
| + if (specificOnly && currentDomain.empty()) |
| + break; |
| + |
| + auto filters = mFiltersByDomain.find(currentDomain); |
| + if (filters) |
| + { |
| + for (auto& entry : filters->second) |
| + { |
| + if (entry.first.is_invalid()) |
| + continue; |
| + |
| + if (seenFilters.find(entry.first)) |
| + continue; |
| + seenFilters.insert(entry.first); |
| + |
| + auto filter = entry.second; |
| + if (filter && !GetException(*filter, docDomain)) |
| + selectors->push_back(filter); |
| + } |
| + } |
| + |
| + if (currentDomain.empty()) |
| + break; |
| + |
| + auto nextDot = currentDomain.find('.'); |
| + currentDomain = nextDot == String::npos ? |
| + u""_str : DependentString(currentDomain, nextDot + 1); |
| + } |
| + |
| + return selectors; |
| +} |