| Index: src/plugin/WebBrowserEventsListener.cpp |
| diff --git a/src/plugin/WebBrowserEventsListener.cpp b/src/plugin/WebBrowserEventsListener.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ac51387bdde8ed80ad038f64b23f4d76f9d550de |
| --- /dev/null |
| +++ b/src/plugin/WebBrowserEventsListener.cpp |
| @@ -0,0 +1,164 @@ |
| +/* |
| + * This file is part of Adblock Plus <https://adblockplus.org/>, |
| + * Copyright (C) 2006-2016 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 "PluginStdAfx.h" |
| +#include "WebBrowserEventsListener.h" |
| + |
| +WebBrowserEventsListener::WebBrowserEventsListener() |
| + : m_isDocumentEvents2Connected(false) |
| + , m_state(State::FirstTimeLoading) |
| +{ |
| +} |
| + |
| +WebBrowserEventsListener::~WebBrowserEventsListener() |
| +{ |
| +} |
| + |
| +HRESULT STDMETHODCALLTYPE WebBrowserEventsListener::OnDocumentComplete(IDispatch* dispFrameBrowser, VARIANT* /*variantUrl*/) |
| +{ |
| + if (!dispFrameBrowser) |
| + { |
| + return E_POINTER; |
| + } |
| + |
| + // if it's a signal from another browser (sub-frame for-example) then ignore it. |
| + if (!m_browser.IsEqualObject(dispFrameBrowser)) |
| + { |
| + return S_OK; |
| + } |
| + |
| + if (!m_isDocumentEvents2Connected) |
| + { |
| + ATL::CComPtr<IDispatch> dispDocument; |
| + ATL::CComQIPtr<IHTMLDocument2> htmlDocument2; |
| + bool isHtmlDocument2 = SUCCEEDED(m_browser->get_Document(&dispDocument)) && (htmlDocument2 = dispDocument); |
| + isHtmlDocument2 && (m_isDocumentEvents2Connected = SUCCEEDED(HTMLDocumentEvents2Listener::DispEventAdvise(htmlDocument2))); |
| + } |
| + |
| + // We can get here when readyStateChanged("complete") is already received, |
| + // don't emit reloaded, because it's already emitted from OnReadyStateChange. |
| + if (m_state == State::FirstTimeLoading) |
| + { |
| + m_state = State::Loaded; |
| + emitReloaded(); |
| + } |
| + return S_OK; |
| +} |
| + |
| +void STDMETHODCALLTYPE WebBrowserEventsListener::OnOnQuit() |
|
Oleksandr
2016/09/30 15:29:20
OnOnQuit sounds somewhat meta. How about just OnQu
|
| +{ |
| + if (m_isDocumentEvents2Connected) |
| + { |
| + ATL::CComPtr<IDispatch> dispDocument; |
| + ATL::CComQIPtr<IHTMLDocument2> htmlDocument2; |
| + if (SUCCEEDED(m_browser->get_Document(&dispDocument)) && (htmlDocument2 = dispDocument)) |
| + { |
| + HTMLDocumentEvents2Listener::DispEventUnadvise(htmlDocument2); |
| + } |
| + } |
| + WebBrowserEvents2Listener::DispEventUnadvise(m_browser); |
| +} |
| + |
| +void STDMETHODCALLTYPE WebBrowserEventsListener::OnReadyStateChange(IHTMLEventObj* /*pEvtObj*/) |
| +{ |
| + auto documentReadyState = [this]()->std::wstring |
| + { |
| + std::wstring notAvailableReadyState; |
| + ATL::CComPtr<IDispatch> pDocDispatch; |
| + m_browser->get_Document(&pDocDispatch); |
| + ATL::CComQIPtr<IHTMLDocument2> htmlDocument2 = pDocDispatch; |
| + if (!htmlDocument2) |
| + { |
| + assert(false && "htmlDocument2 in OnReadyStateChange should not be nullptr"); |
| + return notAvailableReadyState; |
| + } |
| + ATL::CComBSTR readyState; |
| + if (FAILED(htmlDocument2->get_readyState(&readyState)) || !readyState) |
| + { |
| + assert(false && "cannot obtain document readyState in OnReadyStateChange"); |
| + return notAvailableReadyState; |
| + } |
| + return std::wstring(readyState, readyState.Length()); |
| + }(); |
| + if (documentReadyState == L"loading") |
| + { |
| + m_state = State::Loading; |
| + } |
| + else if (documentReadyState == L"interactive") |
| + { |
| + } |
| + else if (documentReadyState == L"complete") |
| + { |
| + if (m_state == State::Loading) |
| + { |
| + m_state = State::Loaded; |
| + emitReloaded(); |
| + } |
| + else if (m_state == State::Loaded) |
| + { |
| + // It happens but very rearely, most often it appears on gmail. |
| + // It seems IE prepares the 'browser' and then immediately says |
| + // "complete" with the new URL. However all cases are related to |
| + // some redirection technique and I could not reproduce it with local |
| + // server which redirects, so let's wait for the user response on another |
| + // web site when an advertisement is not blocked to better investigate |
| + // when it happens. |
| + } |
| + else |
| + { |
| + assert(false); |
| + } |
| + } |
| + else if (documentReadyState == L"uninitialized") |
| + { |
| + } |
| + else |
| + { |
| + assert(false); |
| + } |
| +} |
| + |
| +void WebBrowserEventsListener::FinalRelease() |
| +{ |
| + if (!!m_onDestroy) |
| + { |
| + m_onDestroy(); |
| + } |
| +} |
| + |
| +HRESULT WebBrowserEventsListener::Init(IWebBrowser2* webBrowser, const OnDestroy& onDestroy, const OnReloaded& onReloaded) |
| +{ |
| + if (!(m_browser = webBrowser)) |
| + { |
| + return E_POINTER; |
| + } |
| + m_onDestroy = onDestroy; |
| + m_onReloaded = onReloaded; |
| + if (FAILED(WebBrowserEvents2Listener::DispEventAdvise(m_browser, &DIID_DWebBrowserEvents2))) |
| + { |
| + return E_FAIL; |
| + } |
| + return S_OK; |
| +} |
| + |
| +void WebBrowserEventsListener::emitReloaded() |
| +{ |
| + if (m_onReloaded) |
| + { |
| + m_onReloaded(); |
| + } |
| +} |