Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: src/plugin/PluginTabBase.cpp

Issue 6567422169448448: Issue 119 - Switch to injecting CSS for element hiding (Closed)
Patch Set: rebase, improve memory handling (OnQuit) and improve code organizing Created April 27, 2016, 1:10 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/plugin/PluginTabBase.cpp
diff --git a/src/plugin/PluginTabBase.cpp b/src/plugin/PluginTabBase.cpp
index 011c5b5b673e158c18dc40170e361e56b83d3ef0..e1e9940209e52da2114872c9cf14473c0e411f3b 100644
--- a/src/plugin/PluginTabBase.cpp
+++ b/src/plugin/PluginTabBase.cpp
@@ -23,14 +23,69 @@
#include "PluginTabBase.h"
#include "IeVersion.h"
#include "../shared/Utils.h"
+#include "../shared/EventWithSetter.h"
#include <Mshtmhst.h>
+#include <mutex>
+
+class CPluginTab::AsyncPluginFilter
+{
+public:
+ static std::shared_ptr<AsyncPluginFilter> CreateAsync(const std::wstring& domain)
+ {
+ std::shared_ptr<AsyncPluginFilter> asyncFilter = std::make_shared<AsyncPluginFilter>();
+ std::weak_ptr<AsyncPluginFilter> weakAsyncData = asyncFilter;
+ auto eventSetter = asyncFilter->event.CreateSetter();
+ try
+ {
+ std::thread([domain, weakAsyncData, eventSetter]
+ {
+ try
+ {
+ CreateAsyncImpl(domain, weakAsyncData, eventSetter);
+ }
+ catch (...)
+ {
+ // As a thread-main function, we truncate any C++ exception.
+ }
+ }).detach();
+ // TODO: we should do something with that `detach` above.
+ }
+ catch (const std::system_error& ex)
+ {
+ DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_MAIN_THREAD_CREATE_PROCESS,
+ "Class::Thread - Failed to start filter loader thread");
+ }
+ return asyncFilter;
+ }
+ PluginFilterPtr GetFilter()
+ {
+ if (!event.Wait())
+ return PluginFilterPtr();
+ std::lock_guard<std::mutex> lock(mutex);
+ return filter;
+ }
+private:
+ static void CreateAsyncImpl(const std::wstring& domain, std::weak_ptr<AsyncPluginFilter> weakAsyncData, const std::shared_ptr<EventWithSetter::Setter>& setter)
+ {
+ std::unique_ptr<CPluginFilter> pluginFilter(new CPluginFilter(CPluginClient::GetInstance()->GetElementHidingSelectors(domain)));
+ if (auto asyncData = weakAsyncData.lock())
+ {
+ {
+ std::lock_guard<std::mutex> lock(asyncData->mutex);
+ asyncData->filter = move(pluginFilter);
+ }
+ setter->Set();
+ }
+ }
+ EventWithSetter event;
+ std::mutex mutex;
+ PluginFilterPtr filter;
+};
CPluginTab::CPluginTab()
: m_isActivated(false)
, m_continueThreadRunning(true)
{
- m_filter.hideFiltersLoadedEvent = CreateEvent(NULL, true, false, NULL);
-
CPluginClient* client = CPluginClient::GetInstance();
if (AdblockPlus::IE::InstalledMajorVersion() < 10)
{
@@ -46,14 +101,11 @@ CPluginTab::CPluginTab()
DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_TAB_THREAD_CREATE_PROCESS,
"Tab::Thread - Failed to create tab thread");
}
- m_traverser = new CPluginDomTraverser(static_cast<CPluginTab*>(this));
}
CPluginTab::~CPluginTab()
{
- delete m_traverser;
- m_traverser = NULL;
m_continueThreadRunning = false;
if (m_thread.joinable()) {
m_thread.join();
@@ -82,40 +134,13 @@ void CPluginTab::OnUpdate()
m_isActivated = true;
}
-namespace
-{
- // Entry Point
- void FilterLoader(CPluginFilter* filter, const std::wstring& domain)
- {
- try
- {
- filter->LoadHideFilters(CPluginClient::GetInstance()->GetElementHidingSelectors(domain));
- SetEvent(filter->hideFiltersLoadedEvent);
- }
- catch (...)
- {
- // As a thread-main function, we truncate any C++ exception.
- }
- }
-}
-
void CPluginTab::OnNavigate(const std::wstring& url)
{
SetDocumentUrl(url);
- ClearFrameCache(GetDocumentDomain());
- std::wstring domainString = GetDocumentDomain();
- ResetEvent(m_filter.hideFiltersLoadedEvent);
- try
- {
- std::thread filterLoaderThread(&FilterLoader, &m_filter, GetDocumentDomain());
- filterLoaderThread.detach(); // TODO: but actually we should wait for the thread in the dtr.
- }
- catch (const std::system_error& ex)
- {
- DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_MAIN_THREAD_CREATE_PROCESS,
- "Class::Thread - Failed to start filter loader thread");
- }
- m_traverser->ClearCache();
+ std::wstring domain = GetDocumentDomain();
+ ClearFrameCache(domain);
+ m_asyncPluginFilter = AsyncPluginFilter::CreateAsync(domain);
+ m_traverser.reset();
}
namespace
@@ -213,6 +238,119 @@ void CPluginTab::InjectABP(IWebBrowser2* browser)
}
}
+bool CPluginTab::IsTraverserEnabled()
+{
+ return !IsCSSInjectionEnabled();
+}
+
+bool CPluginTab::IsCSSInjectionEnabled()
+{
+ return IsWindowsVistaOrLater() && AdblockPlus::IE::InstalledMajorVersion() >= 10;
+}
+
+namespace
+{
+ void InjectABPCSS(IHTMLDocument2& htmlDocument2, const std::vector<std::wstring>& hideFilters)
+ {
+ // pseudocode: styleHtmlElement = htmlDocument2.createElement("style");
+ ATL::CComQIPtr<IHTMLStyleElement> styleHtmlElement;
+ {
+ ATL::CComPtr<IHTMLElement> stylePureHtmlElement;
+ if (FAILED(htmlDocument2.createElement(ATL::CComBSTR(L"style"), &stylePureHtmlElement)))
+ {
+ DEBUG_GENERAL(L"Cannot create style element");
+ return;
+ }
+ if (!(styleHtmlElement = stylePureHtmlElement))
+ {
+ DEBUG_GENERAL(L"Cannot obtain IHTMLStyleElement from IHTMLElement");
+ return;
+ }
+ }
+ // pseudocode: styleHtmlElement.type = "text/css";
+ if (FAILED(styleHtmlElement->put_type(ATL::CComBSTR("text/css"))))
+ {
+ DEBUG_GENERAL(L"Cannot set type text/css");
+ return;
+ }
+ // pseudocode: styleSheet4 = styleHtmlElement.sheet;
+ ATL::CComQIPtr<IHTMLStyleSheet4> styleSheet4;
+ {
+ // IHTMLStyleElement2 is availabe starting from IE9, Vista
+ ATL::CComQIPtr<IHTMLStyleElement2> styleHtmlElement2 = styleHtmlElement;
+ if (!styleHtmlElement2)
+ {
+ DEBUG_GENERAL(L"Cannot obtain IHTMLStyleElement2 from IHTMLStyleElement");
+ return;
+ }
+ ATL::CComQIPtr<IHTMLStyleSheet> styleSheet;
+ if (FAILED(styleHtmlElement2->get_sheet(&styleSheet)) || !styleSheet)
+ {
+ DEBUG_GENERAL(L"Cannot obtain IHTMLStyleSheet");
+ return;
+ }
+ // IHTMLStyleSheet4 is availabe starting from IE9, Vista
+ styleSheet4 = styleSheet;
+ if (!styleSheet4)
+ {
+ DEBUG_GENERAL(L"Cannot obtain IHTMLStyleSheet4");
+ return;
+ }
+ }
+ // pseudocode: for (auto i = 0; i < hideFilters.length; ++i) {
+ // pseudocode: i = styleSheet4.insertRule(hideFilters + cssValue, i);
+ // pseudocode: }
+ long newIndex = 0;
+ std::wstring cssValue = L"{ display: none !important; }";
+ for (const auto& selector : hideFilters)
+ {
+ auto cssRule = selector + cssValue;
+ ATL::CComBSTR selector(cssRule.size(), cssRule.c_str());
+ if (SUCCEEDED(styleSheet4->insertRule(selector, newIndex, &newIndex)))
+ {
+ ++newIndex;
+ }
+ else
+ {
+ DEBUG_GENERAL(L"Cannot add rule for selector " + cssRule);
+ }
+ }
+
+ // pseudocode: htmlDocument2.head.appendChild(styleHtmlElement);
+ {
+ // IHTMLDocument7 is availabe starting from IE9, Vista
+ ATL::CComQIPtr<IHTMLDocument7> htmlDocument7 = &htmlDocument2;
+ if (!htmlDocument7)
+ {
+ DEBUG_GENERAL(L"Cannot obtain IHTMLDocument7 from htmlDocument2");
+ return;
+ }
+ ATL::CComPtr<IHTMLElement> headHtmlElement;
+ if (FAILED(htmlDocument7->get_head(&headHtmlElement)))
+ {
+ DEBUG_GENERAL(L"Cannot obtain head from pDoc7");
+ return;
+ }
+ ATL::CComQIPtr<IHTMLDOMNode> headNode = headHtmlElement;
+ if (!headNode)
+ {
+ DEBUG_GENERAL(L"Cannot obtain headNode from headHtmlElement");
+ return;
+ }
+ ATL::CComQIPtr<IHTMLDOMNode> styleNode = styleHtmlElement;
+ if (!styleNode)
+ {
+ DEBUG_GENERAL(L"Cannot obtain IHTMLDOMNode from stylePureHtmlElement");
+ return;
+ }
+ if (FAILED(headNode->appendChild(styleNode, nullptr)))
+ {
+ DEBUG_GENERAL(L"Cannot append blocking style");
+ }
+ }
+ }
+}
+
namespace
{
ATL::CComPtr<IWebBrowser2> GetParent(IWebBrowser2& browser)
@@ -261,11 +399,27 @@ namespace
void CPluginTab::OnDownloadComplete(IWebBrowser2* browser)
{
- CPluginClient* client = CPluginClient::GetInstance();
- std::wstring url = GetDocumentUrl();
- if (!client->IsWhitelistedUrl(url) && !client->IsElemhideWhitelistedOnDomain(url))
+ if (IsTraverserEnabled())
{
- m_traverser->TraverseDocument(browser, GetDocumentDomain(), GetDocumentUrl());
+ CPluginClient* client = CPluginClient::GetInstance();
+ std::wstring url = GetDocumentUrl();
+ if (!client->IsWhitelistedUrl(url) && !client->IsElemhideWhitelistedOnDomain(url))
+ {
+ if (!m_traverser)
+ {
+ assert(m_asyncPluginFilter && "Filter initialization should be already at least started");
+ if (m_asyncPluginFilter)
+ {
+ auto pluginFilter = m_asyncPluginFilter->GetFilter();
+ assert(pluginFilter && "Plugin filter should be a valid object");
+ if (pluginFilter)
+ m_traverser.reset(new CPluginDomTraverser(pluginFilter));
+ }
+ }
+ assert(m_traverser && "Traverser should be a valid object");
+ if (m_traverser)
+ m_traverser->TraverseDocument(browser, GetDocumentDomain(), GetDocumentUrl());
+ }
}
InjectABP(browser);
}
@@ -300,6 +454,24 @@ void CPluginTab::OnDocumentComplete(IWebBrowser2* browser, const std::wstring& u
return;
}
+ if (IsCSSInjectionEnabled() && CPluginSettings::GetInstance()->GetPluginEnabled())
+ {
+ if (!IsFrameWhiteListed(browser))
+ {
+ DEBUG_GENERAL(L"Inject CSS into " + url);
+ assert(m_asyncPluginFilter && "Filter initialization should be already at least started");
+ if (m_asyncPluginFilter)
+ {
+ auto pluginFilter = m_asyncPluginFilter->GetFilter();
+ assert(pluginFilter && "Plugin filter should be a valid object");
+ if (pluginFilter)
+ {
+ InjectABPCSS(*pDoc, pluginFilter->GetHideFilters());
+ }
+ }
+ }
+ }
+
CComPtr<IOleObject> pOleObj;
pDocDispatch->QueryInterface(&pOleObj);
if (!pOleObj)

Powered by Google App Engine
This is Rietveld