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

Delta Between Two Patch Sets: src/plugin/PluginTabBase.cpp

Issue 29323611: Issue #1234, #2058 - Rewrite log facility, improving thread implementation
Left Patch Set: Created Aug. 19, 2015, 5:42 p.m.
Right Patch Set: rebase only Created July 27, 2016, 9:11 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « src/plugin/PluginTabBase.h ('k') | test/plugin/ActiveQueueTest.cpp » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH 3 * Copyright (C) 2006-2016 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 #include "PluginStdAfx.h" 18 #include "PluginStdAfx.h"
19 #include "AdblockPlusClient.h" 19 #include "AdblockPlusClient.h"
20 #include "PluginSettings.h" 20 #include "PluginSettings.h"
21 #include "AdblockPlusDomTraverser.h" 21 #include "AdblockPlusDomTraverser.h"
22 #include "PluginTabBase.h" 22 #include "PluginTabBase.h"
23 #include "IeVersion.h" 23 #include "IeVersion.h"
24 #include "../shared/Utils.h"
24 #include <Mshtmhst.h> 25 #include <Mshtmhst.h>
25 26
26 CPluginTabBase::CPluginTabBase(CPluginClass* plugin) 27 CPluginTab::CPluginTab()
27 : m_plugin(plugin) 28 {
28 { 29 m_filter.hideFiltersLoadedEvent = CreateEvent(NULL, true, false, NULL);
29 m_filter = std::auto_ptr<CPluginFilter>(new CPluginFilter());
30 m_filter->hideFiltersLoadedEvent = CreateEvent(NULL, true, false, NULL);
31 30
32 CPluginClient* client = CPluginClient::GetInstance(); 31 CPluginClient* client = CPluginClient::GetInstance();
33 m_traverser = new CPluginDomTraverser(static_cast<CPluginTab*>(this)); 32 m_traverser = new CPluginDomTraverser(static_cast<CPluginTab*>(this));
34 } 33 }
35 34
36 35 CPluginTab::~CPluginTab()
37 CPluginTabBase::~CPluginTabBase()
38 { 36 {
39 delete m_traverser; 37 delete m_traverser;
40 m_traverser = NULL; 38 m_traverser = NULL;
39 /**
40 * ABP only intercepts protocols "http:" and "https:".
41 * We can disable any domain used in those protocol with an appropriate whitelis t filter.
42 * Thus, the possibility to disable on a particular site depends only on the pro tocol.
43 */
44 bool CPluginTab::IsPossibleToDisableOnSite()
45 {
46 auto url = GetDocumentUrl();
47 return BeginsWith(url, L"http:") || BeginsWith(url, L"https:");
48 }
49
41 } 50 }
42 51
43 namespace 52 namespace
44 { 53 {
45 // Entry Point 54 // Entry Point
46 void FilterLoader(CPluginTabBase* tabBase) 55 void FilterLoader(CPluginFilter* filter, const std::wstring& domain)
47 { 56 {
48 try 57 try
49 { 58 {
50 tabBase->m_filter->LoadHideFilters(CPluginClient::GetInstance()->GetElemen tHidingSelectors(tabBase->GetDocumentDomain())); 59 filter->LoadHideFilters(CPluginClient::GetInstance()->GetElementHidingSele ctors(domain));
51 SetEvent(tabBase->m_filter->hideFiltersLoadedEvent); 60 SetEvent(filter->hideFiltersLoadedEvent);
52 } 61 }
53 catch (...) 62 catch (...)
54 { 63 {
55 // As a thread-main function, we truncate any C++ exception. 64 // As a thread-main function, we truncate any C++ exception.
56 } 65 }
57 } 66 }
58 } 67 }
59 68
60 void CPluginTabBase::OnNavigate(const std::wstring& url) 69 void CPluginTab::OnNavigate(const std::wstring& url)
61 { 70 {
62 SetDocumentUrl(url); 71 SetDocumentUrl(url);
63 ClearFrameCache(GetDocumentDomain()); 72 ClearFrameCache(GetDocumentDomain());
64 std::wstring domainString = GetDocumentDomain(); 73 std::wstring domainString = GetDocumentDomain();
65 ResetEvent(m_filter->hideFiltersLoadedEvent); 74 ResetEvent(m_filter.hideFiltersLoadedEvent);
66 try 75 try
67 { 76 {
68 std::thread filterLoaderThread(&FilterLoader, this); 77 std::thread filterLoaderThread(&FilterLoader, &m_filter, GetDocumentDomain() );
69 filterLoaderThread.detach(); // TODO: but actually we should wait for the th read in the dtr. 78 filterLoaderThread.detach(); // TODO: but actually we should wait for the th read in the dtr.
70 } 79 }
71 catch (const std::system_error& ex) 80 catch (const std::system_error& ex)
72 { 81 {
73 DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_MAIN_THREAD_CRE ATE_PROCESS, 82 DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_MAIN_THREAD_CRE ATE_PROCESS,
74 "Class::Thread - Failed to start filter loader thread"); 83 "Class::Thread - Failed to start filter loader thread");
75 } 84 }
76 m_traverser->ClearCache(); 85 m_traverser->ClearCache();
77 } 86 }
78 87
79 void CPluginTabBase::InjectABP(IWebBrowser2* browser) 88 namespace
89 {
90 /**
91 * Determine if the HTML file is one of ours.
92 * The criterion is that it appear in the "html/templates" folder within our i nstallation.
93 *
94 * Warning: This function may fail if the argument is not a "file://" URL.
95 * This is occasionally the case in circumstances yet to be characterized.
96 */
97 bool IsOurHtmlFile(const std::wstring& url)
98 {
99 // Declared static because the value is derived from an installation directo ry, which won't change during run-time.
100 static auto dir = FileUrl(HtmlFolderPath());
101
102 DEBUG_GENERAL([&]() -> std::wstring {
103 std::wstring log = L"InjectABP. Current URL: ";
104 log += url;
105 log += L", template directory URL: ";
106 log += dir;
107 return log;
108 }());
109
110 /*
111 * The length check here is defensive, in case the document URL is truncated for some reason.
112 */
113 if (url.length() < 5)
114 {
115 // We can't match ".html" at the end of the URL if it's too short.
116 return false;
117 }
118 auto urlCstr = url.c_str();
119 // Check the prefix to match our directory
120 // Check the suffix to be an HTML file
121 return (_wcsnicmp(urlCstr, dir.c_str(), dir.length()) == 0) &&
122 (_wcsnicmp(urlCstr + url.length() - 5, L".html", 5) == 0);
123 }
124 }
125
126 void CPluginTab::InjectABP(IWebBrowser2* browser)
80 { 127 {
81 CriticalSection::Lock lock(m_csInject); 128 CriticalSection::Lock lock(m_csInject);
82 auto url = GetDocumentUrl(); 129 auto url = GetDocumentUrl();
83 130 if (!IsOurHtmlFile(url))
84 std::wstring log = L"InjectABP. Current URL: "; 131 {
85 log += url; 132 DEBUG_GENERAL(L"InjectABP. Not injecting");
86 log += L", settings URL: "; 133 return;
87 log += UserSettingsFileUrl(); 134 }
88 DEBUG_GENERAL(log); 135 DEBUG_GENERAL(L"InjectABP. Injecting");
89
90 CString urlLegacy = ToCString(url);
91 if (!(0 == urlLegacy.CompareNoCase(CString(UserSettingsFileUrl().c_str())) ||
92 0 == urlLegacy.CompareNoCase(CString(FirstRunPageFileUrl().c_str()))))
93 {
94 DEBUG_GENERAL(L"Not injecting");
95 return;
96 }
97 DEBUG_GENERAL(L"Going to inject");
98 CComPtr<IDispatch> pDocDispatch; 136 CComPtr<IDispatch> pDocDispatch;
99 browser->get_Document(&pDocDispatch); 137 browser->get_Document(&pDocDispatch);
100 CComQIPtr<IHTMLDocument2> pDoc2 = pDocDispatch; 138 CComQIPtr<IHTMLDocument2> pDoc2(pDocDispatch);
101 if (!pDoc2) 139 if (!pDoc2)
102 { 140 {
103 DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CRE ATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to QI docume nt"); 141 DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CRE ATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTab::InjectABP - Failed to QI document") ;
104 return; 142 return;
105 } 143 }
106 CComPtr<IHTMLWindow2> pWnd2; 144 CComPtr<IHTMLWindow2> pWnd2;
107 pDoc2->get_parentWindow(&pWnd2); 145 pDoc2->get_parentWindow(&pWnd2);
108 if (!pWnd2) 146 if (!pWnd2)
109 { 147 {
110 DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CRE ATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to get paren t window"); 148 DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CRE ATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTab::InjectABP - Failed to get parent wi ndow");
111 return; 149 return;
112 } 150 }
113 CComQIPtr<IDispatchEx> pWndEx = pWnd2; 151 CComQIPtr<IDispatchEx> pWndEx(pWnd2);
114 if (!pWndEx) 152 if (!pWndEx)
115 { 153 {
116 DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CRE ATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to QI dispat ch"); 154 DEBUG_ERROR_LOG(0, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CRE ATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTab::InjectABP - Failed to QI dispatch") ;
117 return; 155 return;
118 } 156 }
119 // Create "Settings" object in JavaScript. 157 // Create "Settings" object in JavaScript.
120 // A method call of "Settings" in JavaScript, transfered to "Invoke" of m_plug inUserSettings 158 // A method call of "Settings" in JavaScript, transfered to "Invoke" of m_plug inUserSettings
121 DISPID dispid; 159 DISPID dispid;
122 HRESULT hr = pWndEx->GetDispID(L"Settings", fdexNameEnsure, &dispid); 160 HRESULT hr = pWndEx->GetDispID(L"Settings", fdexNameEnsure, &dispid);
123 if (FAILED(hr)) 161 if (FAILED(hr))
124 { 162 {
125 DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CR EATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to get disp atch"); 163 DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CR EATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTab::InjectABP - Failed to get dispatch ");
126 return; 164 return;
127 } 165 }
128 CComVariant var((IDispatch*)&m_pluginUserSettings); 166 CComVariant var((IDispatch*)&m_pluginUserSettings);
129 167
130 DEBUG_GENERAL("Injecting"); 168 DEBUG_GENERAL("Injecting");
131 169
132 DISPPARAMS params; 170 DISPPARAMS params;
133 params.cArgs = 1; 171 params.cArgs = 1;
134 params.cNamedArgs = 0; 172 params.cNamedArgs = 0;
135 params.rgvarg = &var; 173 params.rgvarg = &var;
136 params.rgdispidNamedArgs = 0; 174 params.rgdispidNamedArgs = 0;
137 hr = pWndEx->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPU T | DISPATCH_PROPERTYPUTREF, &params, 0, 0, 0); 175 hr = pWndEx->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPU T | DISPATCH_PROPERTYPUTREF, &params, 0, 0, 0);
138 DEBUG_GENERAL("Invoke"); 176 DEBUG_GENERAL("Invoke");
139 if (FAILED(hr)) 177 if (FAILED(hr))
140 { 178 {
141 DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CR EATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTabBase::InjectABP - Failed to create S ettings in JavaScript"); 179 DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_CREATE_SETTINGS_JAVASCRIPT, PLUGIN_ERROR_CR EATE_SETTINGS_JAVASCRIPT_INVOKE, "CPluginTab::InjectABP - Failed to create Setti ngs in JavaScript");
142 } 180 }
143 } 181 }
144 182
145 void CPluginTabBase::OnDownloadComplete(IWebBrowser2* browser) 183 namespace
184 {
185 ATL::CComPtr<IWebBrowser2> GetParent(IWebBrowser2& browser)
186 {
187 ATL::CComPtr<IDispatch> parentDispatch;
188 if (FAILED(browser.get_Parent(&parentDispatch)) || !parentDispatch)
189 {
190 return nullptr;
191 }
192 // The InternetExplorer application always returns a pointer to itself.
193 // https://msdn.microsoft.com/en-us/library/aa752136(v=vs.85).aspx
194 if (parentDispatch.IsEqualObject(&browser))
195 {
196 return nullptr;
197 }
198 ATL::CComQIPtr<IServiceProvider> parentDocumentServiceProvider = parentDispa tch;
199 if (!parentDocumentServiceProvider)
200 {
201 return nullptr;
202 }
203 ATL::CComPtr<IWebBrowser2> parentBrowser;
204 if (FAILED(parentDocumentServiceProvider->QueryService(SID_SWebBrowserApp, & parentBrowser)))
205 {
206 return nullptr;
207 }
208 return parentBrowser;
209 }
210
211 bool IsFrameWhiteListed(ATL::CComPtr<IWebBrowser2> frame)
212 {
213 if (!frame)
214 {
215 return false;
216 }
217 auto url = GetLocationUrl(*frame);
218 std::vector<std::string> frameHierarchy;
219 while(frame = GetParent(*frame))
220 {
221 frameHierarchy.push_back(ToUtf8String(GetLocationUrl(*frame)));
222 }
223 CPluginClient* client = CPluginClient::GetInstance();
224 return client->IsWhitelistedUrl(url, frameHierarchy)
225 || client->IsElemhideWhitelistedOnDomain(url, frameHierarchy);
226 }
227 }
228
229 void CPluginTab::OnDownloadComplete(IWebBrowser2* browser)
146 { 230 {
147 CPluginClient* client = CPluginClient::GetInstance(); 231 CPluginClient* client = CPluginClient::GetInstance();
148 std::wstring url = GetDocumentUrl(); 232 std::wstring url = GetDocumentUrl();
149 if (!client->IsWhitelistedUrl(url) && !client->IsElemhideWhitelistedOnDomain(u rl)) 233 if (!client->IsWhitelistedUrl(url) && !client->IsElemhideWhitelistedOnDomain(u rl))
150 { 234 {
151 m_traverser->TraverseDocument(browser, GetDocumentDomain(), GetDocumentUrl() ); 235 m_traverser->TraverseDocument(browser, GetDocumentDomain(), GetDocumentUrl() );
152 } 236 }
153 InjectABP(browser); 237 InjectABP(browser);
154 } 238 }
155 239
156 void CPluginTabBase::OnDocumentComplete(IWebBrowser2* browser, const std::wstrin g& url, bool isDocumentBrowser) 240 void CPluginTab::OnDocumentComplete(IWebBrowser2* browser, const std::wstring& u rl, bool isDocumentBrowser)
157 { 241 {
158 std::wstring documentUrl = GetDocumentUrl(); 242 std::wstring documentUrl = GetDocumentUrl();
159 243
160 if (isDocumentBrowser) 244 if (isDocumentBrowser)
161 { 245 {
162 if (url != documentUrl) 246 if (url != documentUrl)
163 { 247 {
164 SetDocumentUrl(url); 248 SetDocumentUrl(url);
165 } 249 }
166 InjectABP(browser); 250 InjectABP(browser);
167 } 251 }
168 CString urlLegacy = ToCString(url); 252 if (BeginsWith(url, L"res://"))
169 if (urlLegacy.Left(6) != "res://") 253 {
170 { 254 return;
171 // Get document 255 }
172 CComPtr<IDispatch> pDocDispatch; 256 // Get document
173 HRESULT hr = browser->get_Document(&pDocDispatch); 257 CComPtr<IDispatch> pDocDispatch;
174 if (FAILED(hr) || !pDocDispatch) 258 HRESULT hr = browser->get_Document(&pDocDispatch);
175 { 259 if (FAILED(hr) || !pDocDispatch)
176 return; 260 {
177 } 261 return;
178 262 }
179 CComQIPtr<IHTMLDocument2> pDoc = pDocDispatch; 263
180 if (!pDoc) 264 CComQIPtr<IHTMLDocument2> pDoc(pDocDispatch);
181 { 265 if (!pDoc)
182 return; 266 {
183 } 267 return;
184 CComPtr<IOleObject> pOleObj; 268 }
185 269
186 pDocDispatch->QueryInterface(IID_IOleObject, (void**)&pOleObj); 270 CComPtr<IOleObject> pOleObj;
187 271 pDocDispatch->QueryInterface(&pOleObj);
188 272 if (!pOleObj)
189 CComPtr<IOleClientSite> pClientSite; 273 {
190 pOleObj->GetClientSite(&pClientSite); 274 return;
191 if (pClientSite != NULL) 275 }
192 { 276 CComPtr<IOleClientSite> pClientSite;
193 CComPtr<IDocHostUIHandler> docHostUIHandler; 277 pOleObj->GetClientSite(&pClientSite);
194 pClientSite->QueryInterface(IID_IDocHostUIHandler, (void**)&docHostUIHandl er); 278 if (pClientSite != NULL)
195 if (docHostUIHandler != NULL) 279 {
196 { 280 CComPtr<IDocHostUIHandler> docHostUIHandler;
197 docHostUIHandler->UpdateUI(); 281 pClientSite->QueryInterface(&docHostUIHandler);
198 } 282 if (docHostUIHandler != NULL)
199 } 283 {
200 } 284 docHostUIHandler->UpdateUI();
201 } 285 }
202 286 }
203 std::wstring CPluginTabBase::GetDocumentDomain() 287 }
288
289 std::wstring CPluginTab::GetDocumentDomain()
204 { 290 {
205 std::wstring domain; 291 std::wstring domain;
206 292
207 m_criticalSection.Lock(); 293 m_criticalSection.Lock();
208 { 294 {
209 domain = m_documentDomain; 295 domain = m_documentDomain;
210 } 296 }
211 m_criticalSection.Unlock(); 297 m_criticalSection.Unlock();
212 298
213 return domain; 299 return domain;
214 } 300 }
215 301
216 void CPluginTabBase::SetDocumentUrl(const std::wstring& url) 302 void CPluginTab::SetDocumentUrl(const std::wstring& url)
217 { 303 {
218 m_criticalSection.Lock(); 304 m_criticalSection.Lock();
219 { 305 {
220 m_documentUrl = url; 306 m_documentUrl = url;
221 m_documentDomain = CAdblockPlusClient::GetInstance()->GetHostFromUrl(url); 307 m_documentDomain = CAdblockPlusClient::GetInstance()->GetHostFromUrl(url);
222 } 308 }
223 m_criticalSection.Unlock(); 309 m_criticalSection.Unlock();
224 } 310 }
225 311
226 std::wstring CPluginTabBase::GetDocumentUrl() 312 std::wstring CPluginTab::GetDocumentUrl()
227 { 313 {
228 std::wstring url; 314 std::wstring url;
229 315
230 m_criticalSection.Lock(); 316 m_criticalSection.Lock();
231 { 317 {
232 url = m_documentUrl; 318 url = m_documentUrl;
233 } 319 }
234 m_criticalSection.Unlock(); 320 m_criticalSection.Unlock();
235 321
236 return url; 322 return url;
237 } 323 }
238 324
239 325
240 // ============================================================================ 326 // ============================================================================
241 // Frame caching 327 // Frame caching
242 // ============================================================================ 328 // ============================================================================
243 bool CPluginTabBase::IsFrameCached(const std::wstring& url) 329 bool CPluginTab::IsFrameCached(const std::wstring& url)
244 { 330 {
245 bool isFrame; 331 bool isFrame;
246 332
247 m_criticalSectionCache.Lock(); 333 m_criticalSectionCache.Lock();
248 { 334 {
249 isFrame = m_cacheFrames.find(url) != m_cacheFrames.end(); 335 isFrame = m_cacheFrames.find(url) != m_cacheFrames.end();
250 } 336 }
251 m_criticalSectionCache.Unlock(); 337 m_criticalSectionCache.Unlock();
252 338
253 return isFrame; 339 return isFrame;
254 } 340 }
255 341
256 void CPluginTabBase::CacheFrame(const std::wstring& url) 342 void CPluginTab::CacheFrame(const std::wstring& url)
257 { 343 {
258 m_criticalSectionCache.Lock(); 344 m_criticalSectionCache.Lock();
259 { 345 {
260 m_cacheFrames.insert(url); 346 m_cacheFrames.insert(url);
261 } 347 }
262 m_criticalSectionCache.Unlock(); 348 m_criticalSectionCache.Unlock();
263 } 349 }
264 350
265 void CPluginTabBase::ClearFrameCache(const std::wstring& domain) 351 void CPluginTab::ClearFrameCache(const std::wstring& domain)
266 { 352 {
267 m_criticalSectionCache.Lock(); 353 m_criticalSectionCache.Lock();
268 { 354 {
269 if (domain.empty() || domain != m_cacheDomain) 355 if (domain.empty() || domain != m_cacheDomain)
270 { 356 {
271 m_cacheFrames.clear(); 357 m_cacheFrames.clear();
272 m_cacheDomain = domain; 358 m_cacheDomain = domain;
273 } 359 }
274 } 360 }
275 m_criticalSectionCache.Unlock(); 361 m_criticalSectionCache.Unlock();
276 } 362 }
277 363
LEFTRIGHT

Powered by Google App Engine
This is Rietveld