| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Implementation of ChromeActiveDocument | |
| 6 #include "chrome_frame/chrome_active_document.h" | |
| 7 | |
| 8 #include <hlink.h> | |
| 9 #include <htiface.h> | |
| 10 #include <initguid.h> | |
| 11 #include <mshtmcid.h> | |
| 12 #include <shdeprecated.h> | |
| 13 #include <shlguid.h> | |
| 14 #include <shlobj.h> | |
| 15 #include <shobjidl.h> | |
| 16 #include <tlogstg.h> | |
| 17 #include <urlmon.h> | |
| 18 #include <wininet.h> | |
| 19 | |
| 20 #include "base/command_line.h" | |
| 21 #include "base/debug/trace_event.h" | |
| 22 #include "base/logging.h" | |
| 23 #include "base/strings/string_util.h" | |
| 24 #include "base/strings/utf_string_conversions.h" | |
| 25 #include "base/win/scoped_variant.h" | |
| 26 #include "chrome/app/chrome_command_ids.h" | |
| 27 #include "chrome/app/chrome_dll_resource.h" | |
| 28 #include "chrome/common/automation_messages.h" | |
| 29 #include "chrome/common/chrome_constants.h" | |
| 30 #include "chrome/test/automation/browser_proxy.h" | |
| 31 #include "chrome/test/automation/tab_proxy.h" | |
| 32 #include "chrome_frame/bho.h" | |
| 33 #include "chrome_frame/bind_context_info.h" | |
| 34 #include "chrome_frame/buggy_bho_handling.h" | |
| 35 #include "chrome_frame/crash_reporting/crash_metrics.h" | |
| 36 #include "chrome_frame/utils.h" | |
| 37 #include "content/public/browser/invalidate_type.h" | |
| 38 #include "content/public/browser/navigation_type.h" | |
| 39 #include "content/public/browser/web_contents.h" | |
| 40 #include "content/public/common/page_zoom.h" | |
| 41 #include "grit/generated_resources.h" | |
| 42 | |
| 43 DEFINE_GUID(CGID_DocHostCmdPriv, 0x000214D4L, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, | |
| 44 0x46); | |
| 45 | |
| 46 bool g_first_launch_by_process_ = true; | |
| 47 | |
| 48 const DWORD kIEEncodingIdArray[] = { | |
| 49 #define DEFINE_ENCODING_ID_ARRAY(encoding_name, id, chrome_name) encoding_name, | |
| 50 INTERNAL_IE_ENCODINGMENU_IDS(DEFINE_ENCODING_ID_ARRAY) | |
| 51 #undef DEFINE_ENCODING_ID_ARRAY | |
| 52 0 // The Last data must be 0 to indicate the end of the encoding id array. | |
| 53 }; | |
| 54 | |
| 55 ChromeActiveDocument::ChromeActiveDocument() | |
| 56 : first_navigation_(true), | |
| 57 is_automation_client_reused_(false), | |
| 58 popup_allowed_(false), | |
| 59 accelerator_table_(NULL) { | |
| 60 TRACE_EVENT_BEGIN_ETW("chromeframe.createactivedocument", this, ""); | |
| 61 | |
| 62 url_fetcher_->set_frame_busting(false); | |
| 63 } | |
| 64 | |
| 65 HRESULT ChromeActiveDocument::FinalConstruct() { | |
| 66 // The FinalConstruct implementation in the ChromeFrameActivexBase class | |
| 67 // i.e. Base creates an instance of the ChromeFrameAutomationClient class | |
| 68 // and initializes it, which would spawn a new Chrome process, etc. | |
| 69 // We don't want to be doing this if we have a cached document, whose | |
| 70 // automation client instance can be reused. | |
| 71 HRESULT hr = BaseActiveX::FinalConstruct(); | |
| 72 if (FAILED(hr)) | |
| 73 return hr; | |
| 74 | |
| 75 InitializeAutomationSettings(); | |
| 76 | |
| 77 find_dialog_.Init(automation_client_.get()); | |
| 78 | |
| 79 OLECMDF flags = static_cast<OLECMDF>(OLECMDF_ENABLED | OLECMDF_SUPPORTED); | |
| 80 | |
| 81 null_group_commands_map_[OLECMDID_PRINT] = flags; | |
| 82 null_group_commands_map_[OLECMDID_FIND] = flags; | |
| 83 null_group_commands_map_[OLECMDID_CUT] = flags; | |
| 84 null_group_commands_map_[OLECMDID_COPY] = flags; | |
| 85 null_group_commands_map_[OLECMDID_PASTE] = flags; | |
| 86 null_group_commands_map_[OLECMDID_SELECTALL] = flags; | |
| 87 null_group_commands_map_[OLECMDID_SAVEAS] = flags; | |
| 88 | |
| 89 mshtml_group_commands_map_[IDM_BASELINEFONT1] = flags; | |
| 90 mshtml_group_commands_map_[IDM_BASELINEFONT2] = flags; | |
| 91 mshtml_group_commands_map_[IDM_BASELINEFONT3] = flags; | |
| 92 mshtml_group_commands_map_[IDM_BASELINEFONT4] = flags; | |
| 93 mshtml_group_commands_map_[IDM_BASELINEFONT5] = flags; | |
| 94 mshtml_group_commands_map_[IDM_VIEWSOURCE] = flags; | |
| 95 | |
| 96 HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase); | |
| 97 accelerator_table_ = | |
| 98 LoadAccelerators(this_module, | |
| 99 MAKEINTRESOURCE(IDR_CHROME_FRAME_IE_FULL_TAB)); | |
| 100 DCHECK(accelerator_table_ != NULL); | |
| 101 return S_OK; | |
| 102 } | |
| 103 | |
| 104 ChromeActiveDocument::~ChromeActiveDocument() { | |
| 105 DVLOG(1) << __FUNCTION__; | |
| 106 if (find_dialog_.IsWindow()) | |
| 107 find_dialog_.DestroyWindow(); | |
| 108 // ChromeFramePlugin | |
| 109 BaseActiveX::Uninitialize(); | |
| 110 | |
| 111 TRACE_EVENT_END_ETW("chromeframe.createactivedocument", this, ""); | |
| 112 } | |
| 113 | |
| 114 // Override DoVerb | |
| 115 STDMETHODIMP ChromeActiveDocument::DoVerb(LONG verb, | |
| 116 LPMSG msg, | |
| 117 IOleClientSite* active_site, | |
| 118 LONG index, | |
| 119 HWND parent_window, | |
| 120 LPCRECT pos) { | |
| 121 // IE will try and in-place activate us in some cases. This happens when | |
| 122 // the user opens a new IE window with a URL that has us as the DocObject. | |
| 123 // Here we refuse to be activated in-place and we will force IE to UIActivate | |
| 124 // us. | |
| 125 if (OLEIVERB_INPLACEACTIVATE == verb) | |
| 126 return OLEOBJ_E_INVALIDVERB; | |
| 127 // Check if we should activate as a docobject or not | |
| 128 // (client supports IOleDocumentSite) | |
| 129 if (doc_site_) { | |
| 130 switch (verb) { | |
| 131 case OLEIVERB_SHOW: { | |
| 132 base::win::ScopedComPtr<IDocHostUIHandler> doc_host_handler; | |
| 133 doc_host_handler.QueryFrom(doc_site_); | |
| 134 if (doc_host_handler.get()) | |
| 135 doc_host_handler->ShowUI(DOCHOSTUITYPE_BROWSE, this, this, NULL, NULL); | |
| 136 } | |
| 137 case OLEIVERB_OPEN: | |
| 138 case OLEIVERB_UIACTIVATE: | |
| 139 if (!m_bUIActive) | |
| 140 return doc_site_->ActivateMe(NULL); | |
| 141 break; | |
| 142 } | |
| 143 } | |
| 144 return IOleObjectImpl<ChromeActiveDocument>::DoVerb(verb, | |
| 145 msg, | |
| 146 active_site, | |
| 147 index, | |
| 148 parent_window, | |
| 149 pos); | |
| 150 } | |
| 151 | |
| 152 // Override IOleInPlaceActiveObjectImpl::OnDocWindowActivate | |
| 153 STDMETHODIMP ChromeActiveDocument::OnDocWindowActivate(BOOL activate) { | |
| 154 DVLOG(1) << __FUNCTION__; | |
| 155 return S_OK; | |
| 156 } | |
| 157 | |
| 158 STDMETHODIMP ChromeActiveDocument::TranslateAccelerator(MSG* msg) { | |
| 159 DVLOG(1) << __FUNCTION__; | |
| 160 if (msg == NULL) | |
| 161 return E_POINTER; | |
| 162 | |
| 163 if (msg->message == WM_KEYDOWN && msg->wParam == VK_TAB) { | |
| 164 HWND focus = ::GetFocus(); | |
| 165 if (focus != m_hWnd && !::IsChild(m_hWnd, focus)) { | |
| 166 // The call to SetFocus triggers a WM_SETFOCUS that makes the base class | |
| 167 // set focus to the correct element in Chrome. | |
| 168 ::SetFocus(m_hWnd); | |
| 169 return S_OK; | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 return S_FALSE; | |
| 174 } | |
| 175 // Override IPersistStorageImpl::IsDirty | |
| 176 STDMETHODIMP ChromeActiveDocument::IsDirty() { | |
| 177 DVLOG(1) << __FUNCTION__; | |
| 178 return S_FALSE; | |
| 179 } | |
| 180 | |
| 181 void ChromeActiveDocument::OnAutomationServerReady() { | |
| 182 BaseActiveX::OnAutomationServerReady(); | |
| 183 } | |
| 184 | |
| 185 STDMETHODIMP ChromeActiveDocument::Load(BOOL fully_avalable, | |
| 186 IMoniker* moniker_name, | |
| 187 LPBC bind_context, | |
| 188 DWORD mode) { | |
| 189 if (NULL == moniker_name) | |
| 190 return E_INVALIDARG; | |
| 191 | |
| 192 base::win::ScopedComPtr<IOleClientSite> client_site; | |
| 193 if (bind_context) { | |
| 194 base::win::ScopedComPtr<IUnknown> site; | |
| 195 bind_context->GetObjectParam(SZ_HTML_CLIENTSITE_OBJECTPARAM, | |
| 196 site.Receive()); | |
| 197 if (site) | |
| 198 client_site.QueryFrom(site); | |
| 199 } | |
| 200 | |
| 201 if (client_site) { | |
| 202 SetClientSite(client_site); | |
| 203 DoQueryService(IID_INewWindowManager, client_site, | |
| 204 popup_manager_.Receive()); | |
| 205 | |
| 206 // See if mshtml parsed the html header for us. If so, we need to | |
| 207 // clear the browser service flag that we use to indicate that this | |
| 208 // browser instance is navigating to a CF document. | |
| 209 base::win::ScopedComPtr<IBrowserService> browser_service; | |
| 210 DoQueryService(SID_SShellBrowser, client_site, browser_service.Receive()); | |
| 211 if (browser_service) { | |
| 212 bool flagged = CheckForCFNavigation(browser_service, true); | |
| 213 DVLOG_IF(1, flagged) << "Cleared flagged browser service"; | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 NavigationManager* mgr = NavigationManager::GetThreadInstance(); | |
| 218 DLOG_IF(ERROR, !mgr) << "Couldn't get instance of NavigationManager"; | |
| 219 | |
| 220 std::wstring url; | |
| 221 | |
| 222 base::win::ScopedComPtr<BindContextInfo> info; | |
| 223 BindContextInfo::FromBindContext(bind_context, info.Receive()); | |
| 224 DCHECK(info); | |
| 225 if (info && !info->GetUrl().empty()) { | |
| 226 url = info->GetUrl(); | |
| 227 if (mgr) { | |
| 228 // If the original URL contains an anchor, then the URL queried | |
| 229 // from the protocol sink wrapper does not contain the anchor. To | |
| 230 // workaround this we retrieve the anchor from the navigation manager | |
| 231 // and append it to the url retrieved from the protocol sink wrapper. | |
| 232 GURL url_for_anchor(mgr->url()); | |
| 233 if (url_for_anchor.has_ref()) { | |
| 234 url += L"#"; | |
| 235 url += base::UTF8ToWide(url_for_anchor.ref()); | |
| 236 } | |
| 237 } | |
| 238 } else { | |
| 239 // If the original URL contains an anchor, then the URL queried | |
| 240 // from the moniker does not contain the anchor. To workaround | |
| 241 // this we retrieve the URL from our BHO. | |
| 242 url = GetActualUrlFromMoniker(moniker_name, bind_context, | |
| 243 mgr ? mgr->url(): std::wstring()); | |
| 244 } | |
| 245 | |
| 246 ChromeFrameUrl cf_url; | |
| 247 if (!cf_url.Parse(url)) { | |
| 248 DLOG(WARNING) << __FUNCTION__ << " Failed to parse url:" << url; | |
| 249 return E_INVALIDARG; | |
| 250 } | |
| 251 | |
| 252 std::string referrer(mgr ? mgr->referrer() : std::string()); | |
| 253 RendererType renderer_type = cf_url.is_chrome_protocol() ? | |
| 254 RENDERER_TYPE_CHROME_GCF_PROTOCOL : RENDERER_TYPE_UNDETERMINED; | |
| 255 | |
| 256 // With CTransaction patch we have more robust way to grab the referrer for | |
| 257 // each top-level-switch-to-CF request by peeking at our sniffing data | |
| 258 // object that lives inside the bind context. We also remember the reason | |
| 259 // we're rendering the document in Chrome. | |
| 260 if (g_patch_helper.state() == PatchHelper::PATCH_PROTOCOL && info) { | |
| 261 scoped_refptr<ProtData> prot_data = info->get_prot_data(); | |
| 262 if (prot_data) { | |
| 263 referrer = prot_data->referrer(); | |
| 264 renderer_type = prot_data->renderer_type(); | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 // For gcf: URLs allow only about and view-source schemes to pass through for | |
| 269 // further inspection. | |
| 270 bool is_safe_scheme = cf_url.gurl().SchemeIs(chrome::kAboutScheme) || | |
| 271 cf_url.gurl().SchemeIs(content::kViewSourceScheme); | |
| 272 if (cf_url.is_chrome_protocol() && !is_safe_scheme && | |
| 273 !GetConfigBool(false, kAllowUnsafeURLs)) { | |
| 274 DLOG(ERROR) << __FUNCTION__ << " gcf: not allowed:" << url; | |
| 275 return E_INVALIDARG; | |
| 276 } | |
| 277 | |
| 278 if (!LaunchUrl(cf_url, referrer)) { | |
| 279 DLOG(ERROR) << __FUNCTION__ << " Failed to launch url:" << url; | |
| 280 return E_INVALIDARG; | |
| 281 } | |
| 282 | |
| 283 if (!cf_url.is_chrome_protocol() && !cf_url.attach_to_external_tab()) | |
| 284 url_fetcher_->SetInfoForUrl(url.c_str(), moniker_name, bind_context); | |
| 285 | |
| 286 // Log a metric indicating why GCF is rendering in Chrome. | |
| 287 // (Note: we only track the renderer type when using the CTransaction patch. | |
| 288 // When the code for the browser service patch and for the moniker patch is | |
| 289 // removed, this conditional can also go away.) | |
| 290 if (RENDERER_TYPE_UNDETERMINED != renderer_type) { | |
| 291 UMA_LAUNCH_TYPE_COUNT(renderer_type); | |
| 292 } | |
| 293 | |
| 294 return S_OK; | |
| 295 } | |
| 296 | |
| 297 STDMETHODIMP ChromeActiveDocument::Save(IMoniker* moniker_name, | |
| 298 LPBC bind_context, | |
| 299 BOOL remember) { | |
| 300 return E_NOTIMPL; | |
| 301 } | |
| 302 | |
| 303 STDMETHODIMP ChromeActiveDocument::SaveCompleted(IMoniker* moniker_name, | |
| 304 LPBC bind_context) { | |
| 305 return E_NOTIMPL; | |
| 306 } | |
| 307 | |
| 308 STDMETHODIMP ChromeActiveDocument::GetCurMoniker(IMoniker** moniker_name) { | |
| 309 return E_NOTIMPL; | |
| 310 } | |
| 311 | |
| 312 STDMETHODIMP ChromeActiveDocument::GetClassID(CLSID* class_id) { | |
| 313 if (NULL == class_id) | |
| 314 return E_POINTER; | |
| 315 *class_id = GetObjectCLSID(); | |
| 316 return S_OK; | |
| 317 } | |
| 318 | |
| 319 STDMETHODIMP ChromeActiveDocument::QueryStatus(const GUID* cmd_group_guid, | |
| 320 ULONG number_of_commands, | |
| 321 OLECMD commands[], | |
| 322 OLECMDTEXT* command_text) { | |
| 323 DVLOG(1) << __FUNCTION__; | |
| 324 | |
| 325 CommandStatusMap* command_map = NULL; | |
| 326 | |
| 327 if (cmd_group_guid) { | |
| 328 if (IsEqualGUID(*cmd_group_guid, GUID_NULL)) { | |
| 329 command_map = &null_group_commands_map_; | |
| 330 } else if (IsEqualGUID(*cmd_group_guid, CGID_MSHTML)) { | |
| 331 command_map = &mshtml_group_commands_map_; | |
| 332 } else if (IsEqualGUID(*cmd_group_guid, CGID_Explorer)) { | |
| 333 command_map = &explorer_group_commands_map_; | |
| 334 } else if (IsEqualGUID(*cmd_group_guid, CGID_ShellDocView)) { | |
| 335 command_map = &shdoc_view_group_commands_map_; | |
| 336 } | |
| 337 } else { | |
| 338 command_map = &null_group_commands_map_; | |
| 339 } | |
| 340 | |
| 341 if (!command_map) { | |
| 342 DVLOG(1) << "unsupported command group: " << GuidToString(*cmd_group_guid); | |
| 343 return OLECMDERR_E_NOTSUPPORTED; | |
| 344 } | |
| 345 | |
| 346 for (ULONG command_index = 0; command_index < number_of_commands; | |
| 347 command_index++) { | |
| 348 DVLOG(1) << "Command id = " << commands[command_index].cmdID; | |
| 349 CommandStatusMap::iterator index = | |
| 350 command_map->find(commands[command_index].cmdID); | |
| 351 if (index != command_map->end()) | |
| 352 commands[command_index].cmdf = index->second; | |
| 353 } | |
| 354 return S_OK; | |
| 355 } | |
| 356 | |
| 357 STDMETHODIMP ChromeActiveDocument::Exec(const GUID* cmd_group_guid, | |
| 358 DWORD command_id, | |
| 359 DWORD cmd_exec_opt, | |
| 360 VARIANT* in_args, | |
| 361 VARIANT* out_args) { | |
| 362 DVLOG(1) << __FUNCTION__ << " Cmd id =" << command_id; | |
| 363 // Bail out if we have been uninitialized. | |
| 364 if (automation_client_.get() && automation_client_->tab()) { | |
| 365 return ProcessExecCommand(cmd_group_guid, command_id, cmd_exec_opt, | |
| 366 in_args, out_args); | |
| 367 } else if (command_id == OLECMDID_REFRESH && cmd_group_guid == NULL) { | |
| 368 // If the automation server has crashed and the user is refreshing the | |
| 369 // page, let OnRefreshPage attempt to recover. | |
| 370 OnRefreshPage(cmd_group_guid, command_id, cmd_exec_opt, in_args, out_args); | |
| 371 } | |
| 372 | |
| 373 return OLECMDERR_E_NOTSUPPORTED; | |
| 374 } | |
| 375 | |
| 376 STDMETHODIMP ChromeActiveDocument::LoadHistory(IStream* stream, | |
| 377 IBindCtx* bind_context) { | |
| 378 // Read notes in ChromeActiveDocument::SaveHistory | |
| 379 DCHECK(stream); | |
| 380 LARGE_INTEGER offset = {0}; | |
| 381 ULARGE_INTEGER cur_pos = {0}; | |
| 382 STATSTG statstg = {0}; | |
| 383 | |
| 384 stream->Seek(offset, STREAM_SEEK_CUR, &cur_pos); | |
| 385 stream->Stat(&statstg, STATFLAG_NONAME); | |
| 386 | |
| 387 DWORD url_size = statstg.cbSize.LowPart - cur_pos.LowPart; | |
| 388 base::win::ScopedBstr url_bstr; | |
| 389 DWORD bytes_read = 0; | |
| 390 stream->Read(url_bstr.AllocateBytes(url_size), url_size, &bytes_read); | |
| 391 std::wstring url(url_bstr); | |
| 392 | |
| 393 ChromeFrameUrl cf_url; | |
| 394 if (!cf_url.Parse(url)) { | |
| 395 DLOG(WARNING) << __FUNCTION__ << " Failed to parse url:" << url; | |
| 396 return E_INVALIDARG; | |
| 397 } | |
| 398 | |
| 399 if (!LaunchUrl(cf_url, std::string())) { | |
| 400 NOTREACHED() << __FUNCTION__ << " Failed to launch url:" << url; | |
| 401 return E_INVALIDARG; | |
| 402 } | |
| 403 return S_OK; | |
| 404 } | |
| 405 | |
| 406 STDMETHODIMP ChromeActiveDocument::SaveHistory(IStream* stream) { | |
| 407 return E_INVALIDARG; | |
| 408 } | |
| 409 | |
| 410 STDMETHODIMP ChromeActiveDocument::SetPositionCookie(DWORD position_cookie) { | |
| 411 return S_OK; | |
| 412 } | |
| 413 | |
| 414 STDMETHODIMP ChromeActiveDocument::GetPositionCookie(DWORD* position_cookie) { | |
| 415 return S_OK; | |
| 416 } | |
| 417 | |
| 418 STDMETHODIMP ChromeActiveDocument::GetUrlForEvents(BSTR* url) { | |
| 419 if (NULL == url) | |
| 420 return E_POINTER; | |
| 421 *url = ::SysAllocString(url_); | |
| 422 return S_OK; | |
| 423 } | |
| 424 | |
| 425 STDMETHODIMP ChromeActiveDocument::GetAddressBarUrl(BSTR* url) { | |
| 426 return GetUrlForEvents(url); | |
| 427 } | |
| 428 | |
| 429 STDMETHODIMP ChromeActiveDocument::Reset() { | |
| 430 next_privacy_record_ = privacy_info_.privacy_records.begin(); | |
| 431 return S_OK; | |
| 432 } | |
| 433 | |
| 434 STDMETHODIMP ChromeActiveDocument::GetSize(DWORD* size) { | |
| 435 if (!size) | |
| 436 return E_POINTER; | |
| 437 | |
| 438 *size = privacy_info_.privacy_records.size(); | |
| 439 return S_OK; | |
| 440 } | |
| 441 | |
| 442 STDMETHODIMP ChromeActiveDocument::GetPrivacyImpacted(BOOL* privacy_impacted) { | |
| 443 if (!privacy_impacted) | |
| 444 return E_POINTER; | |
| 445 | |
| 446 *privacy_impacted = privacy_info_.privacy_impacted; | |
| 447 return S_OK; | |
| 448 } | |
| 449 | |
| 450 STDMETHODIMP ChromeActiveDocument::Next(BSTR* url, BSTR* policy, | |
| 451 LONG* reserved, DWORD* flags) { | |
| 452 if (!url || !policy || !flags) | |
| 453 return E_POINTER; | |
| 454 | |
| 455 if (next_privacy_record_ == privacy_info_.privacy_records.end()) | |
| 456 return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); | |
| 457 | |
| 458 *url = SysAllocString(next_privacy_record_->first.c_str()); | |
| 459 *policy = SysAllocString(next_privacy_record_->second.policy_ref.c_str()); | |
| 460 *flags = next_privacy_record_->second.flags; | |
| 461 | |
| 462 next_privacy_record_++; | |
| 463 return S_OK; | |
| 464 } | |
| 465 | |
| 466 bool ChromeActiveDocument::IsSchemeAllowed(const GURL& url) { | |
| 467 bool allowed = BaseActiveX::IsSchemeAllowed(url); | |
| 468 if (allowed) | |
| 469 return true; | |
| 470 | |
| 471 if (url.SchemeIs(chrome::kAboutScheme)) { | |
| 472 if (LowerCaseEqualsASCII(url.spec(), chrome::kAboutPluginsURL)) | |
| 473 return true; | |
| 474 } | |
| 475 return false; | |
| 476 } | |
| 477 | |
| 478 HRESULT ChromeActiveDocument::GetInPlaceFrame( | |
| 479 IOleInPlaceFrame** in_place_frame) { | |
| 480 DCHECK(in_place_frame); | |
| 481 if (in_place_frame_) { | |
| 482 *in_place_frame = in_place_frame_.get(); | |
| 483 (*in_place_frame)->AddRef(); | |
| 484 return S_OK; | |
| 485 } else { | |
| 486 return S_FALSE; | |
| 487 } | |
| 488 } | |
| 489 | |
| 490 HRESULT ChromeActiveDocument::IOleObject_SetClientSite( | |
| 491 IOleClientSite* client_site) { | |
| 492 if (client_site == NULL) { | |
| 493 base::win::ScopedComPtr<IDocHostUIHandler> doc_host_handler; | |
| 494 if (doc_site_) | |
| 495 doc_host_handler.QueryFrom(doc_site_); | |
| 496 | |
| 497 if (doc_host_handler.get()) | |
| 498 doc_host_handler->HideUI(); | |
| 499 | |
| 500 doc_site_.Release(); | |
| 501 } | |
| 502 | |
| 503 if (client_site != m_spClientSite) | |
| 504 return BaseActiveX::IOleObject_SetClientSite(client_site); | |
| 505 | |
| 506 return S_OK; | |
| 507 } | |
| 508 | |
| 509 HRESULT ChromeActiveDocument::ActiveXDocActivate(LONG verb) { | |
| 510 HRESULT hr = S_OK; | |
| 511 m_bNegotiatedWnd = TRUE; | |
| 512 if (!m_bInPlaceActive) { | |
| 513 hr = m_spInPlaceSite->CanInPlaceActivate(); | |
| 514 if (FAILED(hr)) | |
| 515 return hr; | |
| 516 m_spInPlaceSite->OnInPlaceActivate(); | |
| 517 } | |
| 518 m_bInPlaceActive = TRUE; | |
| 519 // get location in the parent window, | |
| 520 // as well as some information about the parent | |
| 521 base::win::ScopedComPtr<IOleInPlaceUIWindow> in_place_ui_window; | |
| 522 frame_info_.cb = sizeof(OLEINPLACEFRAMEINFO); | |
| 523 HWND parent_window = NULL; | |
| 524 if (m_spInPlaceSite->GetWindow(&parent_window) == S_OK) { | |
| 525 in_place_frame_.Release(); | |
| 526 RECT position_rect = {0}; | |
| 527 RECT clip_rect = {0}; | |
| 528 m_spInPlaceSite->GetWindowContext(in_place_frame_.Receive(), | |
| 529 in_place_ui_window.Receive(), | |
| 530 &position_rect, | |
| 531 &clip_rect, | |
| 532 &frame_info_); | |
| 533 if (!m_bWndLess) { | |
| 534 if (IsWindow()) { | |
| 535 ::ShowWindow(m_hWnd, SW_SHOW); | |
| 536 SetFocus(); | |
| 537 } else { | |
| 538 m_hWnd = Create(parent_window, position_rect); | |
| 539 if (!IsWindow()) { | |
| 540 // This might happen if the automation server couldn't be | |
| 541 // instantiated. If so, a NOTREACHED() will have already been hit. | |
| 542 DLOG(ERROR) << "Failed to create Ax window"; | |
| 543 return AtlHresultFromLastError(); | |
| 544 } | |
| 545 } | |
| 546 } | |
| 547 SetObjectRects(&position_rect, &clip_rect); | |
| 548 } | |
| 549 | |
| 550 base::win::ScopedComPtr<IOleInPlaceActiveObject> in_place_active_object(this); | |
| 551 | |
| 552 // Gone active by now, take care of UIACTIVATE | |
| 553 if (DoesVerbUIActivate(verb)) { | |
| 554 if (!m_bUIActive) { | |
| 555 m_bUIActive = TRUE; | |
| 556 hr = m_spInPlaceSite->OnUIActivate(); | |
| 557 if (FAILED(hr)) | |
| 558 return hr; | |
| 559 // set ourselves up in the host | |
| 560 if (in_place_active_object) { | |
| 561 if (in_place_frame_) | |
| 562 in_place_frame_->SetActiveObject(in_place_active_object, NULL); | |
| 563 if (in_place_ui_window) | |
| 564 in_place_ui_window->SetActiveObject(in_place_active_object, NULL); | |
| 565 } | |
| 566 } | |
| 567 } | |
| 568 m_spClientSite->ShowObject(); | |
| 569 return S_OK; | |
| 570 } | |
| 571 | |
| 572 bool IsFindAccelerator(const MSG& msg) { | |
| 573 // TODO(robertshield): This may not stand up to localization. Fix if this | |
| 574 // is the case. | |
| 575 return msg.message == WM_KEYDOWN && msg.wParam == 'F' && | |
| 576 base::win::IsCtrlPressed() && | |
| 577 !(base::win::IsAltPressed() || base::win::IsShiftPressed()); | |
| 578 } | |
| 579 | |
| 580 void ChromeActiveDocument::OnFindInPage() { | |
| 581 TabProxy* tab = GetTabProxy(); | |
| 582 if (tab) { | |
| 583 if (!find_dialog_.IsWindow()) | |
| 584 find_dialog_.Create(m_hWnd); | |
| 585 | |
| 586 find_dialog_.ShowWindow(SW_SHOW); | |
| 587 } | |
| 588 } | |
| 589 | |
| 590 void ChromeActiveDocument::OnViewSource() { | |
| 591 } | |
| 592 | |
| 593 void ChromeActiveDocument::OnDetermineSecurityZone(const GUID* cmd_group_guid, | |
| 594 DWORD command_id, | |
| 595 DWORD cmd_exec_opt, | |
| 596 VARIANT* in_args, | |
| 597 VARIANT* out_args) { | |
| 598 // Always return URLZONE_INTERNET since that is the Chrome's behaviour. | |
| 599 // Correct step is to use MapUrlToZone(). | |
| 600 if (out_args != NULL) { | |
| 601 out_args->vt = VT_UI4; | |
| 602 out_args->ulVal = URLZONE_INTERNET; | |
| 603 } | |
| 604 } | |
| 605 | |
| 606 void ChromeActiveDocument::OnDisplayPrivacyInfo() { | |
| 607 privacy_info_ = url_fetcher_->privacy_info(); | |
| 608 Reset(); | |
| 609 DoPrivacyDlg(m_hWnd, url_, this, TRUE); | |
| 610 } | |
| 611 | |
| 612 void ChromeActiveDocument::OnGetZoomRange(const GUID* cmd_group_guid, | |
| 613 DWORD command_id, | |
| 614 DWORD cmd_exec_opt, | |
| 615 VARIANT* in_args, | |
| 616 VARIANT* out_args) { | |
| 617 if (out_args != NULL) { | |
| 618 out_args->vt = VT_I4; | |
| 619 out_args->lVal = 0; | |
| 620 } | |
| 621 } | |
| 622 | |
| 623 bool ChromeActiveDocument::PreProcessContextMenu(HMENU menu) { | |
| 624 base::win::ScopedComPtr<IBrowserService> browser_service; | |
| 625 base::win::ScopedComPtr<ITravelLog> travel_log; | |
| 626 GetBrowserServiceAndTravelLog(browser_service.Receive(), | |
| 627 travel_log.Receive()); | |
| 628 if (!browser_service || !travel_log) | |
| 629 return true; | |
| 630 | |
| 631 EnableMenuItem(menu, IDC_BACK, MF_BYCOMMAND | | |
| 632 (SUCCEEDED(travel_log->GetTravelEntry(browser_service, TLOG_BACK, | |
| 633 NULL)) ? | |
| 634 MF_ENABLED : MF_DISABLED)); | |
| 635 EnableMenuItem(menu, IDC_FORWARD, MF_BYCOMMAND | | |
| 636 (SUCCEEDED(travel_log->GetTravelEntry(browser_service, TLOG_FORE, | |
| 637 NULL)) ? | |
| 638 MF_ENABLED : MF_DISABLED)); | |
| 639 // Call base class (adds 'About' item) | |
| 640 return BaseActiveX::PreProcessContextMenu(menu); | |
| 641 } | |
| 642 | |
| 643 HRESULT ChromeActiveDocument::IEExec(const GUID* cmd_group_guid, | |
| 644 DWORD command_id, DWORD cmd_exec_opt, | |
| 645 VARIANT* in_args, VARIANT* out_args) { | |
| 646 HRESULT hr = E_FAIL; | |
| 647 | |
| 648 base::win::ScopedComPtr<IOleCommandTarget> frame_cmd_target; | |
| 649 | |
| 650 base::win::ScopedComPtr<IOleInPlaceSite> in_place_site(m_spInPlaceSite); | |
| 651 if (!in_place_site.get() && m_spClientSite != NULL) | |
| 652 in_place_site.QueryFrom(m_spClientSite); | |
| 653 | |
| 654 if (in_place_site) | |
| 655 hr = frame_cmd_target.QueryFrom(in_place_site); | |
| 656 | |
| 657 if (frame_cmd_target) { | |
| 658 hr = frame_cmd_target->Exec(cmd_group_guid, command_id, cmd_exec_opt, | |
| 659 in_args, out_args); | |
| 660 } | |
| 661 | |
| 662 return hr; | |
| 663 } | |
| 664 | |
| 665 bool ChromeActiveDocument::LaunchUrl(const ChromeFrameUrl& cf_url, | |
| 666 const std::string& referrer) { | |
| 667 return false; | |
| 668 } | |
| 669 | |
| 670 HRESULT ChromeActiveDocument::OnRefreshPage(const GUID* cmd_group_guid, | |
| 671 DWORD command_id, DWORD cmd_exec_opt, VARIANT* in_args, VARIANT* out_args) { | |
| 672 DVLOG(1) << __FUNCTION__; | |
| 673 popup_allowed_ = false; | |
| 674 if (in_args->vt == VT_I4 && | |
| 675 in_args->lVal & OLECMDIDF_REFRESH_PAGEACTION_POPUPWINDOW) { | |
| 676 popup_allowed_ = true; | |
| 677 | |
| 678 // Ask the yellow security band to change the text and icon and to remain | |
| 679 // visible. | |
| 680 IEExec(&CGID_DocHostCommandHandler, OLECMDID_PAGEACTIONBLOCKED, | |
| 681 0x80000000 | OLECMDIDF_WINDOWSTATE_USERVISIBLE_VALID, NULL, NULL); | |
| 682 } | |
| 683 | |
| 684 NavigationManager* mgr = NavigationManager::GetThreadInstance(); | |
| 685 DLOG_IF(ERROR, !mgr) << "Couldn't get instance of NavigationManager"; | |
| 686 | |
| 687 // If ChromeFrame was activated on this page as a result of a document | |
| 688 // received in response to a top level post, then we ask the user for | |
| 689 // permission to repost and issue a navigation with the saved post data | |
| 690 // which reinitates the whole sequence, i.e. the server receives the top | |
| 691 // level post and chrome frame will be reactivated in response. | |
| 692 if (mgr && mgr->post_data().type() != VT_EMPTY) { | |
| 693 if (MessageBox( | |
| 694 SimpleResourceLoader::Get(IDS_HTTP_POST_WARNING).c_str(), | |
| 695 SimpleResourceLoader::Get(IDS_HTTP_POST_WARNING_TITLE).c_str(), | |
| 696 MB_YESNO | MB_ICONEXCLAMATION) == IDYES) { | |
| 697 base::win::ScopedComPtr<IWebBrowser2> web_browser2; | |
| 698 DoQueryService(SID_SWebBrowserApp, m_spClientSite, | |
| 699 web_browser2.Receive()); | |
| 700 DCHECK(web_browser2); | |
| 701 VARIANT empty = base::win::ScopedVariant::kEmptyVariant; | |
| 702 VARIANT flags = { VT_I4 }; | |
| 703 V_I4(&flags) = navNoHistory; | |
| 704 | |
| 705 return web_browser2->Navigate2(base::win::ScopedVariant(url_).AsInput(), | |
| 706 &flags, | |
| 707 &empty, | |
| 708 const_cast<VARIANT*>(&mgr->post_data()), | |
| 709 const_cast<VARIANT*>(&mgr->headers())); | |
| 710 } else { | |
| 711 return S_OK; | |
| 712 } | |
| 713 } | |
| 714 | |
| 715 TabProxy* tab_proxy = GetTabProxy(); | |
| 716 if (tab_proxy) { | |
| 717 tab_proxy->ReloadAsync(); | |
| 718 } | |
| 719 | |
| 720 return S_OK; | |
| 721 } | |
| 722 | |
| 723 HRESULT ChromeActiveDocument::SetPageFontSize(const GUID* cmd_group_guid, | |
| 724 DWORD command_id, | |
| 725 DWORD cmd_exec_opt, | |
| 726 VARIANT* in_args, | |
| 727 VARIANT* out_args) { | |
| 728 if (!automation_client_.get()) { | |
| 729 NOTREACHED() << "Invalid automation client"; | |
| 730 return E_FAIL; | |
| 731 } | |
| 732 | |
| 733 switch (command_id) { | |
| 734 case IDM_BASELINEFONT1: | |
| 735 automation_client_->SetPageFontSize(SMALLEST_FONT); | |
| 736 break; | |
| 737 | |
| 738 case IDM_BASELINEFONT2: | |
| 739 automation_client_->SetPageFontSize(SMALL_FONT); | |
| 740 break; | |
| 741 | |
| 742 case IDM_BASELINEFONT3: | |
| 743 automation_client_->SetPageFontSize(MEDIUM_FONT); | |
| 744 break; | |
| 745 | |
| 746 case IDM_BASELINEFONT4: | |
| 747 automation_client_->SetPageFontSize(LARGE_FONT); | |
| 748 break; | |
| 749 | |
| 750 case IDM_BASELINEFONT5: | |
| 751 automation_client_->SetPageFontSize(LARGEST_FONT); | |
| 752 break; | |
| 753 | |
| 754 default: | |
| 755 NOTREACHED() << "Invalid font size command: " | |
| 756 << command_id; | |
| 757 return E_FAIL; | |
| 758 } | |
| 759 | |
| 760 // Forward the command back to IEFrame with group set to | |
| 761 // CGID_ExplorerBarDoc. This is probably needed to update the menu state to | |
| 762 // indicate that the font size was set. This currently fails with error | |
| 763 // 0x80040104. | |
| 764 // TODO(iyengar) | |
| 765 // Do some investigation into why this Exec call fails. | |
| 766 IEExec(&CGID_ExplorerBarDoc, command_id, cmd_exec_opt, NULL, NULL); | |
| 767 return S_OK; | |
| 768 } | |
| 769 | |
| 770 HRESULT ChromeActiveDocument::OnEncodingChange(const GUID* cmd_group_guid, | |
| 771 DWORD command_id, | |
| 772 DWORD cmd_exec_opt, | |
| 773 VARIANT* in_args, | |
| 774 VARIANT* out_args) { | |
| 775 const struct EncodingMapData { | |
| 776 DWORD ie_encoding_id; | |
| 777 const char* chrome_encoding_name; | |
| 778 } kEncodingTestDatas[] = { | |
| 779 #define DEFINE_ENCODING_MAP(encoding_name, id, chrome_name) \ | |
| 780 { encoding_name, chrome_name }, | |
| 781 INTERNAL_IE_ENCODINGMENU_IDS(DEFINE_ENCODING_MAP) | |
| 782 #undef DEFINE_ENCODING_MAP | |
| 783 }; | |
| 784 | |
| 785 if (!automation_client_.get()) { | |
| 786 NOTREACHED() << "Invalid automtion client"; | |
| 787 return E_FAIL; | |
| 788 } | |
| 789 | |
| 790 // Using ARRAYSIZE_UNSAFE in here is because we define the struct | |
| 791 // EncodingMapData inside function. | |
| 792 const char* chrome_encoding_name = NULL; | |
| 793 for (int i = 0; i < ARRAYSIZE_UNSAFE(kEncodingTestDatas); ++i) { | |
| 794 const struct EncodingMapData* encoding_data = &kEncodingTestDatas[i]; | |
| 795 if (command_id == encoding_data->ie_encoding_id) { | |
| 796 chrome_encoding_name = encoding_data->chrome_encoding_name; | |
| 797 break; | |
| 798 } | |
| 799 } | |
| 800 // Return E_FAIL when encountering invalid encoding id. | |
| 801 if (!chrome_encoding_name) | |
| 802 return E_FAIL; | |
| 803 | |
| 804 TabProxy* tab = GetTabProxy(); | |
| 805 if (!tab) { | |
| 806 NOTREACHED() << "Can not get TabProxy"; | |
| 807 return E_FAIL; | |
| 808 } | |
| 809 | |
| 810 if (chrome_encoding_name) | |
| 811 tab->OverrideEncoding(chrome_encoding_name); | |
| 812 | |
| 813 // Like we did on SetPageFontSize, we may forward the command back to IEFrame | |
| 814 // to update the menu state to indicate that which encoding was set. | |
| 815 // TODO(iyengar) | |
| 816 // Do some investigation into why this Exec call fails. | |
| 817 IEExec(&CGID_ExplorerBarDoc, command_id, cmd_exec_opt, NULL, NULL); | |
| 818 return S_OK; | |
| 819 } | |
| 820 HRESULT ChromeActiveDocument::GetBrowserServiceAndTravelLog( | |
| 821 IBrowserService** browser_service, ITravelLog** travel_log) { | |
| 822 DCHECK(browser_service || travel_log); | |
| 823 base::win::ScopedComPtr<IBrowserService> browser_service_local; | |
| 824 HRESULT hr = DoQueryService(SID_SShellBrowser, m_spClientSite, | |
| 825 browser_service_local.Receive()); | |
| 826 if (!browser_service_local) { | |
| 827 NOTREACHED() << "DoQueryService for IBrowserService failed: " << hr; | |
| 828 return hr; | |
| 829 } | |
| 830 | |
| 831 if (travel_log) { | |
| 832 hr = browser_service_local->GetTravelLog(travel_log); | |
| 833 DVLOG_IF(1, !travel_log) << "browser_service->GetTravelLog failed: " << hr; | |
| 834 } | |
| 835 | |
| 836 if (browser_service) | |
| 837 *browser_service = browser_service_local.Detach(); | |
| 838 | |
| 839 return hr; | |
| 840 } | |
| 841 | |
| 842 LRESULT ChromeActiveDocument::OnForward(WORD notify_code, WORD id, | |
| 843 HWND control_window, | |
| 844 BOOL& bHandled) { | |
| 845 base::win::ScopedComPtr<IWebBrowser2> web_browser2; | |
| 846 DoQueryService(SID_SWebBrowserApp, m_spClientSite, web_browser2.Receive()); | |
| 847 DCHECK(web_browser2); | |
| 848 | |
| 849 if (web_browser2) | |
| 850 web_browser2->GoForward(); | |
| 851 return 0; | |
| 852 } | |
| 853 | |
| 854 LRESULT ChromeActiveDocument::OnBack(WORD notify_code, WORD id, | |
| 855 HWND control_window, | |
| 856 BOOL& bHandled) { | |
| 857 base::win::ScopedComPtr<IWebBrowser2> web_browser2; | |
| 858 DoQueryService(SID_SWebBrowserApp, m_spClientSite, web_browser2.Receive()); | |
| 859 DCHECK(web_browser2); | |
| 860 | |
| 861 if (web_browser2) | |
| 862 web_browser2->GoBack(); | |
| 863 return 0; | |
| 864 } | |
| 865 | |
| 866 LRESULT ChromeActiveDocument::OnFirePrivacyChange(UINT message, WPARAM wparam, | |
| 867 LPARAM lparam, | |
| 868 BOOL& handled) { | |
| 869 if (!m_spClientSite) | |
| 870 return 0; | |
| 871 | |
| 872 base::win::ScopedComPtr<IWebBrowser2> web_browser2; | |
| 873 DoQueryService(SID_SWebBrowserApp, m_spClientSite, | |
| 874 web_browser2.Receive()); | |
| 875 if (!web_browser2) { | |
| 876 NOTREACHED() << "Failed to retrieve IWebBrowser2 interface."; | |
| 877 return 0; | |
| 878 } | |
| 879 | |
| 880 base::win::ScopedComPtr<IShellBrowser> shell_browser; | |
| 881 DoQueryService(SID_STopLevelBrowser, web_browser2, | |
| 882 shell_browser.Receive()); | |
| 883 DCHECK(shell_browser.get() != NULL); | |
| 884 base::win::ScopedComPtr<ITridentService2> trident_services; | |
| 885 trident_services.QueryFrom(shell_browser); | |
| 886 if (trident_services) | |
| 887 trident_services->FirePrivacyImpactedStateChange(wparam); | |
| 888 else | |
| 889 NOTREACHED() << "Failed to retrieve IWebBrowser2 interface."; | |
| 890 return 0; | |
| 891 } | |
| 892 | |
| 893 LRESULT ChromeActiveDocument::OnShowWindow(UINT message, WPARAM wparam, | |
| 894 LPARAM lparam, | |
| 895 BOOL& handled) { // NO_LINT | |
| 896 if (wparam) | |
| 897 SetFocus(); | |
| 898 return 0; | |
| 899 } | |
| 900 | |
| 901 LRESULT ChromeActiveDocument::OnSetFocus(UINT message, WPARAM wparam, | |
| 902 LPARAM lparam, | |
| 903 BOOL& handled) { // NO_LINT | |
| 904 return 0; | |
| 905 } | |
| OLD | NEW |