Skip to content
Snippets Groups Projects
Commit f781782d authored by slightlyoff@chromium.org's avatar slightlyoff@chromium.org
Browse files

Initial import of the Chrome Frame codebase. Integration in chrome.gyp coming in a separate CL.

BUG=None
TEST=None

Review URL: http://codereview.chromium.org/218019

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27042 0039d316-1c4b-4281-b951-d872f2087c98
parent 63cf4759
No related branches found
No related tags found
No related merge requests found
Showing
with 7104 additions and 0 deletions
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview CFInstall.js provides a set of utilities for managing
* the Chrome Frame detection and installation process.
* @author slightlyoff@google.com (Alex Russell)
*/
(function(scope) {
// bail if we'd be over-writing an existing CFInstall object
if (scope['CFInstall']) {
return;
}
/**
* returns an item based on DOM ID. Optionally a document may be provided to
* specify the scope to search in. If a node is passed, it's returned as-is.
* @param {string|Node} id The ID of the node to be located or a node
* @param {Node} doc Optional A document to search for id.
* @return {Node}
*/
var byId = function(id, doc) {
return (typeof id == 'string') ? (doc || document).getElementById(id) : id;
};
/////////////////////////////////////////////////////////////////////////////
// Plugin Detection
/////////////////////////////////////////////////////////////////////////////
var cachedAvailable;
/**
* Checks to find out if ChromeFrame is available as a plugin
* @return {Boolean}
*/
var isAvailable = function() {
if (typeof cachedAvailable != 'undefined') {
return cachedAvailable;
}
cachedAvailable = false;
// Look for CF in the User Agent before trying more expensive checks
var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf("chromeframe") >= 0 || ua.indexOf("x-clock") >= 0) {
cachedAvailable = true;
return cachedAvailable;
}
if (typeof window['ActiveXObject'] != 'undefined') {
try {
var obj = new ActiveXObject('ChromeTab.ChromeFrame');
if (obj) {
cachedAvailable = true;
}
} catch(e) {
// squelch
}
}
return cachedAvailable;
};
/** @type {boolean} */
var cfStyleTagInjected = false;
/**
* Creates a style sheet in the document which provides default styling for
* ChromeFrame instances. Successive calls should have no additive effect.
*/
var injectCFStyleTag = function() {
if (cfStyleTagInjected) {
// Once and only once
return;
}
try {
var rule = '.chromeFrameInstallDefaultStyle {' +
'width: 500px;' +
'height: 400px;' +
'padding: 0;' +
'border: 1px solid #0028c4;' +
'margin: 0;' +
'}';
var ss = document.createElement('style');
ss.setAttribute('type', 'text/css');
if (ss.styleSheet) {
ss.styleSheet.cssText = rule;
} else {
ss.appendChild(document.createTextNode(rule));
}
var h = document.getElementsByTagName('head')[0];
var firstChild = h.firstChild;
h.insertBefore(ss, firstChild);
cfStyleTagInjected = true;
} catch (e) {
// squelch
}
};
/**
* Plucks properties from the passed arguments and sets them on the passed
* DOM node
* @param {Node} node The node to set properties on
* @param {Object} args A map of user-specified properties to set
*/
var setProperties = function(node, args) {
injectCFStyleTag();
var srcNode = byId(args['node']);
node.id = args['id'] || (srcNode ? srcNode['id'] || getUid(srcNode) : '');
// TODO(slightlyoff): Opera compat? need to test there
var cssText = args['cssText'] || '';
node.style.cssText = ' ' + cssText;
var classText = args['className'] || '';
node.className = 'chromeFrameInstallDefaultStyle ' + classText;
// default if the browser doesn't so we don't show sad-tab
var src = args['src'] || 'about:blank';
node.src = src;
if (srcNode) {
srcNode.parentNode.replaceChild(node, srcNode);
}
};
/**
* Creates an iframe.
* @param {Object} args A bag of configuration properties, including values
* like 'node', 'cssText', 'className', 'id', 'src', etc.
* @return {Node}
*/
var makeIframe = function(args) {
var el = document.createElement('iframe');
setProperties(el, args);
return el;
};
var CFInstall = {};
/**
* Checks to see if Chrome Frame is available, if not, prompts the user to
* install. Once installation is begun, a background timer starts,
* checkinging for a successful install every 2 seconds. Upon detection of
* successful installation, the current page is reloaded, or if a
* 'destination' parameter is passed, the page navigates there instead.
* @param {Object} args A bag of configuration properties. Respected
* properties are: 'mode', 'url', 'destination', 'node', 'onmissing',
* 'preventPrompt', 'oninstall', 'preventInstallDetection', 'cssText', and
* 'className'.
* @public
*/
CFInstall.check = function(args) {
args = args || {};
// We currently only support CF in IE
// TODO(slightlyoff): Update this should we support other browsers!
var ieRe = /MSIE (\S+)/;
if (!ieRe.test(navigator.userAgent)) {
return;
}
// TODO(slightlyoff): Update this URL when a mini-installer page is
// available.
var installUrl = '//www.google.com/chromeframe';
if (!isAvailable()) {
if (args.onmissing) {
args.onmissing();
}
args.src = args.url || installUrl;
var mode = args.mode || 'inline';
var preventPrompt = args.preventPrompt || false;
if (!preventPrompt) {
if (mode == 'inline') {
var ifr = makeIframe(args);
// TODO(slightlyoff): handle placement more elegantly!
if (!ifr.parentNode) {
var firstChild = document.body.firstChild;
document.body.insertBefore(ifr, firstChild);
}
} else {
window.open(args.src);
}
}
if (args.preventInstallDetection) {
return;
}
// Begin polling for install success.
var installTimer = setInterval(function() {
// every 2 seconds, look to see if CF is available, if so, proceed on
// to our destination
if (isAvailable()) {
if (args.oninstall) {
args.oninstall();
}
clearInterval(installTimer);
// TODO(slightlyoff): add a way to prevent navigation or make it
// contingent on oninstall?
window.location = args.destination || window.location;
}
}, 2000);
}
};
CFInstall.isAvailable = isAvailable;
// expose CFInstall to the external scope. We've already checked to make
// sure we're not going to blow existing objects away.
scope.CFInstall = CFInstall;
})(this['ChromeFrameInstallScope'] || this);
This diff is collapsed.
deps = {
# TODO(slightlyoff): need to add to Chromium third_party/ !!
# Chrome Frame needs these gecko SDKs and internals.
"src/third_party/xulrunner-sdk":
"svn://chrome-svn/chrome/trunk/deps/third_party/xulrunner-sdk",
}
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome_frame/bho.h"
#include <shlguid.h>
#include <shobjidl.h>
#include "base/logging.h"
#include "base/registry.h"
#include "base/scoped_bstr_win.h"
#include "base/scoped_comptr_win.h"
#include "base/scoped_variant_win.h"
#include "base/string_util.h"
#include "chrome_tab.h" // NOLINT
#include "chrome_frame/protocol_sink_wrap.h"
#include "chrome_frame/utils.h"
#include "chrome_frame/vtable_patch_manager.h"
const wchar_t kUrlMonDllName[] = L"urlmon.dll";
const wchar_t kPatchProtocols[] = L"PatchProtocols";
static const int kIBrowserServiceOnHttpEquivIndex = 30;
PatchHelper g_patch_helper;
BEGIN_VTABLE_PATCHES(IBrowserService)
VTABLE_PATCH_ENTRY(kIBrowserServiceOnHttpEquivIndex, Bho::OnHttpEquiv)
END_VTABLE_PATCHES()
_ATL_FUNC_INFO Bho::kBeforeNavigate2Info = {
CC_STDCALL, VT_EMPTY, 7, {
VT_DISPATCH,
VT_VARIANT | VT_BYREF,
VT_VARIANT | VT_BYREF,
VT_VARIANT | VT_BYREF,
VT_VARIANT | VT_BYREF,
VT_VARIANT | VT_BYREF,
VT_BOOL | VT_BYREF
}
};
Bho::Bho() {
}
STDMETHODIMP Bho::SetSite(IUnknown* site) {
HRESULT hr = S_OK;
if (site) {
ScopedComPtr<IWebBrowser2> web_browser2;
web_browser2.QueryFrom(site);
if (web_browser2) {
hr = DispEventAdvise(web_browser2, &DIID_DWebBrowserEvents2);
DCHECK(SUCCEEDED(hr)) << "DispEventAdvise failed. Error: " << hr;
}
if (g_patch_helper.state() == PatchHelper::PATCH_IBROWSER) {
ScopedComPtr<IBrowserService> browser_service;
hr = DoQueryService(SID_SShellBrowser, site, browser_service.Receive());
DCHECK(browser_service) << "DoQueryService - SID_SShellBrowser failed."
<< " Site: " << site << " Error: " << hr;
if (browser_service) {
g_patch_helper.PatchBrowserService(browser_service);
DCHECK(SUCCEEDED(hr)) << "vtable_patch::PatchInterfaceMethods failed."
<< " Site: " << site << " Error: " << hr;
}
}
}
return IObjectWithSiteImpl<Bho>::SetSite(site);
}
STDMETHODIMP Bho::BeforeNavigate2(IDispatch* dispatch, VARIANT* url,
VARIANT* flags, VARIANT* target_frame_name, VARIANT* post_data,
VARIANT* headers, VARIANT_BOOL* cancel) {
ScopedComPtr<IWebBrowser2> web_browser2;
if (dispatch)
web_browser2.QueryFrom(dispatch);
if (!web_browser2) {
NOTREACHED() << "Can't find WebBrowser2 with given dispatch";
return S_OK; // Return success, we operate on best effort basis.
}
DLOG(INFO) << "BeforeNavigate2: " << url->bstrVal;
if (g_patch_helper.state() == PatchHelper::PATCH_IBROWSER) {
VARIANT_BOOL is_top_level = VARIANT_FALSE;
web_browser2->get_TopLevelContainer(&is_top_level);
std::wstring current_url;
bool is_chrome_protocol = false;
if (is_top_level && IsValidUrlScheme(url->bstrVal)) {
current_url.assign(url->bstrVal, SysStringLen(url->bstrVal));
is_chrome_protocol = StartsWith(current_url, kChromeProtocolPrefix,
false);
if (!is_chrome_protocol && IsOptInUrl(current_url.c_str())) {
DLOG(INFO) << "Canceling navigation and switching to cf";
// Cancel original navigation
*cancel = VARIANT_TRUE;
// Issue new request with 'cf:'
current_url.insert(0, kChromeProtocolPrefix);
ScopedVariant new_url(current_url.c_str());
HRESULT hr = web_browser2->Navigate2(new_url.AsInput(), flags,
target_frame_name, post_data,
headers);
DCHECK(SUCCEEDED(hr)) << "web_browser2->Navigate2 failed. Error: " << hr
<< std::endl << "Url: " << current_url
<< std::endl << "flags: " << flags
<< std::endl << "post data: " << post_data
<< std::endl << "headers: " << headers;
}
}
}
return S_OK;
}
HRESULT Bho::FinalConstruct() {
return S_OK;
}
void Bho::FinalRelease() {
}
HRESULT STDMETHODCALLTYPE Bho::OnHttpEquiv(
IBrowserService_OnHttpEquiv_Fn original_httpequiv,
IBrowserService* browser, IShellView* shell_view, BOOL done,
VARIANT* in_arg, VARIANT* out_arg) {
if (!done && in_arg && (VT_BSTR == V_VT(in_arg))) {
if (StrStrI(V_BSTR(in_arg), kChromeContentPrefix)) {
// OnHttpEquiv is invoked for meta tags within sub frames as well.
// We want to switch renderers only for the top level frame. Since
// the same |browser| and |shell_view| are passed in to OnHttpEquiv
// even for sub iframes, we determine if this is the top one by
// checking if there are any sub frames created or not.
ScopedComPtr<IWebBrowser2> web_browser2;
DoQueryService(SID_SWebBrowserApp, browser, web_browser2.Receive());
if (web_browser2 && !HasSubFrames(web_browser2))
SwitchRenderer(web_browser2, browser, shell_view, V_BSTR(in_arg));
}
}
return original_httpequiv(browser, shell_view, done, in_arg, out_arg);
}
bool Bho::HasSubFrames(IWebBrowser2* web_browser2) {
bool has_sub_frames = false;
ScopedComPtr<IDispatch> doc_dispatch;
if (web_browser2) {
HRESULT hr = web_browser2->get_Document(doc_dispatch.Receive());
DCHECK(SUCCEEDED(hr) && doc_dispatch) <<
"web_browser2->get_Document failed. Error: " << hr;
ScopedComPtr<IOleContainer> container;
if (SUCCEEDED(hr) && doc_dispatch) {
container.QueryFrom(doc_dispatch);
ScopedComPtr<IEnumUnknown> enumerator;
if (container) {
container->EnumObjects(OLECONTF_EMBEDDINGS, enumerator.Receive());
ScopedComPtr<IUnknown> unk;
ULONG items_retrieved = 0;
if (enumerator)
enumerator->Next(1, unk.Receive(), &items_retrieved);
has_sub_frames = (items_retrieved != 0);
}
}
}
return has_sub_frames;
}
HRESULT Bho::SwitchRenderer(IWebBrowser2* web_browser2,
IBrowserService* browser, IShellView* shell_view,
const wchar_t* meta_tag) {
DCHECK(web_browser2 && browser && shell_view && meta_tag);
// Get access to the mshtml instance and the moniker
ScopedComPtr<IOleObject> mshtml_ole_object;
HRESULT hr = shell_view->GetItemObject(SVGIO_BACKGROUND, IID_IOleObject,
reinterpret_cast<void**>(mshtml_ole_object.Receive()));
if (!mshtml_ole_object) {
NOTREACHED() << "shell_view->GetItemObject failed. Error: " << hr;
return hr;
}
std::wstring url;
ScopedComPtr<IMoniker> moniker;
hr = mshtml_ole_object->GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
OLEWHICHMK_OBJFULL, moniker.Receive());
DCHECK(moniker) << "mshtml_ole_object->GetMoniker failed. Error: " << hr;
if (moniker)
hr = GetUrlFromMoniker(moniker, NULL, &url);
DCHECK(!url.empty()) << "GetUrlFromMoniker failed. Error: " << hr;
DCHECK(!StartsWith(url, kChromeProtocolPrefix, false));
if (!url.empty()) {
url.insert(0, kChromeProtocolPrefix);
// Navigate to new url
VARIANT empty = ScopedVariant::kEmptyVariant;
VARIANT flags = { VT_I4 };
V_I4(&flags) = 0;
ScopedVariant url_var(url.c_str());
hr = web_browser2->Navigate2(url_var.AsInput(), &flags, &empty, &empty,
&empty);
DCHECK(SUCCEEDED(hr)) << "web_browser2->Navigate2 failed. Error: " << hr
<< std::endl << "Url: " << url;
}
return S_OK;
}
void PatchHelper::InitializeAndPatchProtocolsIfNeeded() {
if (state_ != UNKNOWN)
return;
bool patch_protocol = GetConfigBool(true, kPatchProtocols);
if (patch_protocol) {
ProtocolSinkWrap::PatchProtocolHandler(kUrlMonDllName, CLSID_HttpProtocol);
ProtocolSinkWrap::PatchProtocolHandler(kUrlMonDllName, CLSID_HttpSProtocol);
state_ = PATCH_PROTOCOL;
} else {
state_ = PATCH_IBROWSER;
}
}
void PatchHelper::PatchBrowserService(IBrowserService* browser_service) {
DCHECK(state_ == PATCH_IBROWSER);
state_ = PATCH_IBROWSER_OK;
vtable_patch::PatchInterfaceMethods(browser_service,
IBrowserService_PatchInfo);
}
extern vtable_patch::MethodPatchInfo IInternetProtocol_PatchInfo[];
extern vtable_patch::MethodPatchInfo IInternetProtocolEx_PatchInfo[];
void PatchHelper::UnpatchIfNeeded() {
if (state_ == PATCH_PROTOCOL) {
vtable_patch::UnpatchInterfaceMethods(IInternetProtocol_PatchInfo);
vtable_patch::UnpatchInterfaceMethods(IInternetProtocolEx_PatchInfo);
} else if (state_ == PATCH_IBROWSER_OK) {
vtable_patch::UnpatchInterfaceMethods(IBrowserService_PatchInfo);
}
state_ = UNKNOWN;
}
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_FRAME_BHO_H_
#define CHROME_FRAME_BHO_H_
#include <string>
#include <atlbase.h>
#include <atlcom.h>
#include <exdisp.h>
#include <exdispid.h>
#include <mshtml.h>
#include <shdeprecated.h>
#include "chrome_tab.h" // NOLINT
#include "chrome_frame/resource.h"
#include "grit/chrome_frame_resources.h"
class PatchHelper {
public:
enum State { UNKNOWN, PATCH_IBROWSER, PATCH_IBROWSER_OK, PATCH_PROTOCOL };
PatchHelper() : state_(UNKNOWN) {
}
State state() const {
return state_;
}
void InitializeAndPatchProtocolsIfNeeded();
void PatchBrowserService(IBrowserService* p);
void UnpatchIfNeeded();
protected:
State state_;
};
// Single global variable
extern PatchHelper g_patch_helper;
class ATL_NO_VTABLE Bho
: public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<Bho, &CLSID_ChromeFrameBHO>,
public IObjectWithSiteImpl<Bho>,
public IDispEventSimpleImpl<0, Bho, &DIID_DWebBrowserEvents2> {
public:
typedef HRESULT (STDMETHODCALLTYPE* IBrowserService_OnHttpEquiv_Fn)(
IBrowserService* browser, IShellView* shell_view, BOOL done,
VARIANT* in_arg, VARIANT* out_arg);
DECLARE_REGISTRY_RESOURCEID(IDR_BHO)
DECLARE_NOT_AGGREGATABLE(Bho)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(Bho)
COM_INTERFACE_ENTRY(IObjectWithSite)
END_COM_MAP()
BEGIN_SINK_MAP(Bho)
SINK_ENTRY_INFO(0, DIID_DWebBrowserEvents2, DISPID_BEFORENAVIGATE2,
BeforeNavigate2, &kBeforeNavigate2Info)
END_SINK_MAP()
// Lifetime management methods
Bho();
HRESULT FinalConstruct();
void FinalRelease();
// IObjectWithSite
STDMETHODIMP SetSite(IUnknown* site);
STDMETHOD(BeforeNavigate2)(IDispatch* dispatch, VARIANT* url, VARIANT* flags,
VARIANT* target_frame_name, VARIANT* post_data, VARIANT* headers,
VARIANT_BOOL* cancel);
// mshtml sends an IOleCommandTarget::Exec of OLECMDID_HTTPEQUIV
// (and OLECMDID_HTTPEQUIV_DONE) as soon as it parses a meta tag.
// It also sends contents of the meta tag as an argument. IEFrame
// handles this in IBrowserService::OnHttpEquiv. So this allows
// us to sniff the META tag by simply patching it. The renderer
// switching can be achieved by cancelling original navigation
// and issuing a new one using IWebBrowser2->Navigate2.
static HRESULT STDMETHODCALLTYPE OnHttpEquiv(
IBrowserService_OnHttpEquiv_Fn original_httpequiv,
IBrowserService* browser, IShellView* shell_view, BOOL done,
VARIANT* in_arg, VARIANT* out_arg);
protected:
bool PatchProtocolHandler(const CLSID& handler_clsid);
static bool HasSubFrames(IWebBrowser2* web_browser2);
static HRESULT SwitchRenderer(IWebBrowser2* web_browser2,
IBrowserService* browser, IShellView* shell_view,
const wchar_t* meta_tag);
static _ATL_FUNC_INFO kBeforeNavigate2Info;
};
// Add Bho to class library table so IE can CoCreate it.
OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho);
#endif // CHROME_FRAME_BHO_H_
HKLM {
NoRemove SOFTWARE {
NoRemove Classes {
ChromeFrame.Bho.1 = s 'Bho Class' {
CLSID = s '{ECB3C477-1A0A-44bd-BB57-78F9EFE34FA7}'
}
ChromeFrame.Bho = s 'ChromeFrame BHO' {
CLSID = s '{ECB3C477-1A0A-44bd-BB57-78F9EFE34FA7}'
CurVer = s 'ChromeFrame.Bho.1'
}
NoRemove CLSID {
ForceRemove {ECB3C477-1A0A-44bd-BB57-78F9EFE34FA7} = s 'ChromeFrame BHO' {
ProgID = s 'ChromeFrame.Bho.1'
VersionIndependentProgID = s 'ChromeFrame.Bho'
InprocServer32 = s '%MODULE%' {
val ThreadingModel = s 'Apartment'
}
'TypeLib' = s '{6F2664E1-FF6E-488A-BCD1-F4CA6001DFCC}'
}
}
}
}
}
chrome_frame/chrome_active_document.bmp

246 B

This diff is collapsed.
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_FRAME_CHROME_ACTIVE_DOCUMENT_H_
#define CHROME_FRAME_CHROME_ACTIVE_DOCUMENT_H_
#include <atlbase.h>
#include <atlcom.h>
#include <atlctl.h>
#include <map>
#include "base/scoped_ptr.h"
#include "base/scoped_comptr_win.h"
#include "base/thread.h"
#include "chrome_frame/chrome_frame_activex_base.h"
#include "chrome_frame/com_type_info_holder.h"
#include "chrome_frame/find_dialog.h"
#include "chrome_frame/in_place_menu.h"
#include "chrome_frame/ole_document_impl.h"
#include "chrome_frame/resource.h"
#include "chrome_frame/extra_system_apis.h"
class Thread;
class TabProxy;
class ChromeActiveDocument;
// A call to IOleCommandTarget::Exec on the webbrowser with this command id
// and a command group of CGID_EXPLORER causes IE to finalize the current
// travel log entry and move to a new location (pruning any forward entries
// if needed)
#define INTERNAL_CMDID_FINALIZE_TRAVEL_LOG (38)
// To set the lock icon status call IOleCommandTarget::Exec on site with
// this command id and a command group of CGID_EXPLORER The in arg is one of
// the values: SECURELOCK_SET_UNSECURE, SECURELOCK_SET_MIXED,
// SECURELOCK_SET_SECURE128BIT etc declared in shdeprecated.h
#define INTERNAL_CMDID_SET_SSL_LOCK (37)
// A call to IOleCommandTarget::Exec on the webbrowser with this command id
// and a command group of CGID_EXPLORER causes IE to replace the URL in the
// current travel log entry
#define UNDOC_CMDID_REPLACE_CURRENT_TRAVEL_LOG_ENTRY_URL (40)
#define UNDOC_IE_CONTEXTMENU_ADDFAV (2261)
#define UNDOC_IE_CONTEXTMENU_VIEWSOURCE (2139)
#define UNDOC_IE_CONTEXTMENU_REFRESH (6042)
// This macro should be defined in the public section of the class.
#define BEGIN_EXEC_COMMAND_MAP(theClass) \
public: \
HRESULT ProcessExecCommand(const GUID* cmd_group_guid, DWORD command_id, \
DWORD cmd_exec_opt, VARIANT* in_args, \
VARIANT* out_args) { \
HRESULT hr = OLECMDERR_E_NOTSUPPORTED; \
switch (command_id) {
#define EXEC_COMMAND_HANDLER(id, handler) \
case id: { \
hr = S_OK; \
handler(cmd_group_guid, command_id, cmd_exec_opt, in_args, out_args) \
break; \
}
#define EXEC_COMMAND_HANDLER_NO_ARGS(id, handler) \
case id: { \
hr = S_OK; \
handler(); \
break; \
}
#define EXEC_COMMAND_HANDLER_GENERIC(id, code) \
case id: { \
hr = S_OK; \
code; \
break; \
}
#define END_EXEC_COMMAND_MAP() \
default: \
break; \
} \
return hr; \
}
// ChromeActiveDocument: Implementation of the Active Document object that is
// responsible for rendering pages in Chrome. This object delegates to
// Chrome.exe (via the Chrome IPC-based automation mechanism) for the actual
// rendering
class ATL_NO_VTABLE ChromeActiveDocument
: public ChromeFrameActivexBase<ChromeActiveDocument,
CLSID_ChromeActiveDocument>,
public IOleDocumentImpl<ChromeActiveDocument>,
public IOleDocumentViewImpl<ChromeActiveDocument>,
public IPersistMoniker,
public IOleCommandTarget,
public InPlaceMenu<ChromeActiveDocument>,
public IWebBrowserEventsUrlService {
public:
typedef ChromeFrameActivexBase<ChromeActiveDocument,
CLSID_ChromeActiveDocument> Base;
ChromeActiveDocument();
~ChromeActiveDocument();
DECLARE_REGISTRY_RESOURCEID(IDR_CHROMEACTIVEDOCUMENT)
BEGIN_COM_MAP(ChromeActiveDocument)
COM_INTERFACE_ENTRY(IOleDocument)
COM_INTERFACE_ENTRY(IOleDocumentView)
COM_INTERFACE_ENTRY(IPersistMoniker)
COM_INTERFACE_ENTRY(IOleCommandTarget)
COM_INTERFACE_ENTRY(IWebBrowserEventsUrlService)
COM_INTERFACE_ENTRY_CHAIN(Base)
END_COM_MAP()
BEGIN_MSG_MAP(ChromeActiveDocument)
CHAIN_MSG_MAP(Base)
END_MSG_MAP()
HRESULT FinalConstruct();
#define FORWARD_TAB_COMMAND(id, command) \
EXEC_COMMAND_HANDLER_GENERIC(id, GetTabProxy() ? GetTabProxy()->command() : 1)
BEGIN_EXEC_COMMAND_MAP(ChromeActiveDocument)
EXEC_COMMAND_HANDLER_GENERIC(OLECMDID_PRINT, automation_client_->PrintTab())
EXEC_COMMAND_HANDLER_NO_ARGS(OLECMDID_FIND, OnFindInPage)
EXEC_COMMAND_HANDLER_NO_ARGS(UNDOC_IE_CONTEXTMENU_VIEWSOURCE, OnViewSource)
FORWARD_TAB_COMMAND(OLECMDID_SELECTALL, SelectAll)
FORWARD_TAB_COMMAND(OLECMDID_CUT, Cut)
FORWARD_TAB_COMMAND(OLECMDID_COPY, Copy)
FORWARD_TAB_COMMAND(OLECMDID_PASTE, Paste)
FORWARD_TAB_COMMAND(OLECMDID_REFRESH, ReloadAsync)
FORWARD_TAB_COMMAND(OLECMDID_STOP, StopAsync)
END_EXEC_COMMAND_MAP()
// IPCs from automation server.
virtual void OnNavigationStateChanged(int tab_handle, int flags,
const IPC::NavigationInfo& nav_info);
virtual void OnUpdateTargetUrl(int tab_handle,
const std::wstring& new_target_url);
virtual void OnAcceleratorPressed(int tab_handle, const MSG& accel_message);
virtual void OnTabbedOut(int tab_handle, bool reverse);
virtual void OnDidNavigate(int tab_handle,
const IPC::NavigationInfo& nav_info);
void OnFindInPage();
// Override DoVerb
STDMETHOD(DoVerb)(LONG verb,
LPMSG msg,
IOleClientSite* active_site,
LONG index,
HWND parent_window,
LPCRECT pos);
STDMETHOD(InPlaceDeactivate)(void);
// Override IOleInPlaceActiveObjectImpl::OnDocWindowActivate
STDMETHOD(OnDocWindowActivate)(BOOL activate);
STDMETHOD(TranslateAccelerator)(MSG* msg);
// IPersistMoniker methods
STDMETHOD(GetClassID)(CLSID* class_id);
STDMETHOD(IsDirty)();
STDMETHOD(GetCurMoniker)(IMoniker** moniker_name);
STDMETHOD(Load)(BOOL fully_avalable,
IMoniker* moniker_name,
LPBC bind_context,
DWORD mode);
STDMETHOD(Save)(IMoniker* moniker_name,
LPBC bind_context,
BOOL remember);
STDMETHOD(SaveCompleted)(IMoniker* moniker_name,
LPBC bind_context);
// IOleCommandTarget methods
STDMETHOD(QueryStatus)(const GUID* cmd_group_guid,
ULONG number_of_commands,
OLECMD commands[],
OLECMDTEXT* command_text);
STDMETHOD(Exec)(const GUID* cmd_group_guid, DWORD command_id,
DWORD cmd_exec_opt,
VARIANT* in_args,
VARIANT* out_args);
// IWebBrowserEventsUrlService methods
STDMETHOD(GetUrlForEvents)(BSTR* url);
// ChromeFrameActivexBase overrides
HRESULT IOleObject_SetClientSite(IOleClientSite* client_site);
HRESULT ActiveXDocActivate(LONG verb);
// Callbacks from ChromeFramePlugin<T>
bool PreProcessContextMenu(HMENU menu);
bool HandleContextMenuCommand(UINT cmd);
// Should connections initiated by this class try to block
// responses served with the X-Frame-Options header?
bool is_frame_busting_enabled();
protected:
// ChromeFrameActivexBase overrides
virtual void OnOpenURL(int tab_handle, const GURL& url_to_open,
int open_disposition);
virtual void OnLoad(int tab_handle, const GURL& url);
// A helper method that updates our internal navigation state
// as well as IE's navigation state (viz Title and current URL).
// The navigation_flags is a TabContents::InvalidateTypes enum
void UpdateNavigationState(const IPC::NavigationInfo& nav_info);
TabProxy* GetTabProxy() const {
if (automation_client_.get())
return automation_client_->tab();
return NULL;
}
// Exec command handlers
void OnViewSource();
// Call exec on our site's command target
HRESULT IEExec(const GUID* cmd_group_guid, DWORD command_id,
DWORD cmd_exec_opt, VARIANT* in_args, VARIANT* out_args);
protected:
typedef std::map<int, bool> EnabledCommandsMap;
IPC::NavigationInfo navigation_info_;
bool is_doc_object_;
// This indicates whether this is the first navigation in this
// active document. It is initalize to true and it is set to false
// after we get a navigation notification from Chrome
bool first_navigation_;
// Our find dialog
CFFindDialog find_dialog_;
// Contains the list of enabled commands ids.
EnabledCommandsMap enabled_commands_map_;
// Set to true if the automation_client_ member is initialized from
// an existing ChromeActiveDocument instance which is going away and
// a new ChromeActiveDocument instance is taking its place.
bool is_automation_client_reused_;
public:
ScopedComPtr<IOleInPlaceFrame> in_place_frame_;
OLEINPLACEFRAMEINFO frame_info_;
};
OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument)
#endif // CHROME_FRAME_CHROME_ACTIVE_DOCUMENT_H_
HKLM {
NoRemove Software {
NoRemove Classes {
ChromeTab.ChromeActiveDocument.1 = s 'ChromeActiveDocument Class' {
CLSID = s '{3E1D0E7F-F5E3-44CC-AA6A-C0A637619AB8}'
'DocObject' = s '0'
val EditFlags = d '65536'
}
ChromeTab.ChromeActiveDocument = s 'ChromeActiveDocument Class' {
CLSID = s '{3E1D0E7F-F5E3-44CC-AA6A-C0A637619AB8}'
CurVer = s 'ChromeTab.ChromeActiveDocument.1'
}
NoRemove CLSID {
ForceRemove {3E1D0E7F-F5E3-44CC-AA6A-C0A637619AB8} = s 'ChromeActiveDocument Class' {
ProgID = s 'ChromeTab.ChromeActiveDocument.1'
VersionIndependentProgID = s 'ChromeTab.ChromeActiveDocument'
ForceRemove 'Programmable'
InprocServer32 = s '%MODULE%' {
val ThreadingModel = s 'Apartment'
}
val AppID = s '%APPID%'
ForceRemove 'Control'
ForceRemove 'ToolboxBitmap32' = s '%MODULE%, 104'
'DocObject' = s '0'
'MiscStatus' = s '0' {
'1' = s '%OLEMISC%'
}
'TypeLib' = s '{6F2664E1-FF6E-488A-BCD1-F4CA6001DFCC}'
'Version' = s '1.0'
}
}
}
}
}
HKLM {
NoRemove Software {
NoRemove Classes {
NoRemove MIME {
NoRemove Database {
NoRemove s 'Content Type' {
'application/chromepage' {
val CLSID = s '{3E1D0E7F-F5E3-44CC-AA6A-C0A637619AB8}'
}
}
}
}
}
}
}
HKCU {
NoRemove Software {
NoRemove Microsoft {
NoRemove Windows {
NoRemove CurrentVersion {
NoRemove 'Internet Settings' {
NoRemove 'Secure Mime Handlers' {
val ChromeTab.ChromeActiveDocument.1 = d '1'
val ChromeTab.ChromeActiveDocument = d '1'
}
}
}
}
}
}
}
This diff is collapsed.
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome_frame/chrome_frame_activex.h"
#include <shdeprecated.h> // for IBrowserService2
#include <wininet.h>
#include <algorithm>
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/scoped_bstr_win.h"
#include "base/string_util.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/tab_proxy.h"
#include "googleurl/src/gurl.h"
#include "chrome_frame/com_message_event.h"
#include "chrome_frame/utils.h"
ChromeFrameActivex::ChromeFrameActivex() {
}
HRESULT ChromeFrameActivex::FinalConstruct() {
HRESULT hr = Base::FinalConstruct();
if (FAILED(hr))
return hr;
// No need to call FireOnChanged at this point since nobody will be listening.
ready_state_ = READYSTATE_LOADING;
return S_OK;
}
ChromeFrameActivex::~ChromeFrameActivex() {
// We expect these to be released during a call to SetClientSite(NULL).
DCHECK(onmessage_.size() == 0);
DCHECK(onloaderror_.size() == 0);
DCHECK(onload_.size() == 0);
DCHECK(onreadystatechanged_.size() == 0);
}
LRESULT ChromeFrameActivex::OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
BOOL& handled) {
Base::OnCreate(message, wparam, lparam, handled);
return 0;
}
void ChromeFrameActivex::OnAcceleratorPressed(int tab_handle,
const MSG& accel_message) {
DCHECK(m_spInPlaceSite != NULL);
// Allow our host a chance to handle the accelerator.
// This catches things like Ctrl+F, Ctrl+O etc, but not browser
// accelerators such as F11, Ctrl+T etc.
// (see AllowFrameToTranslateAccelerator for those).
HRESULT hr = TranslateAccelerator(const_cast<MSG*>(&accel_message));
if (hr != S_OK)
hr = AllowFrameToTranslateAccelerator(accel_message);
DLOG(INFO) << __FUNCTION__ << " browser response: "
<< StringPrintf("0x%08x", hr);
// Last chance to handle the keystroke is to pass it to chromium.
// We do this last partially because there's no way for us to tell if
// chromium actually handled the keystroke, but also since the browser
// should have first dibs anyway.
if (hr != S_OK && automation_client_.get()) {
TabProxy* tab = automation_client_->tab();
if (tab) {
tab->ProcessUnhandledAccelerator(accel_message);
}
}
}
HRESULT ChromeFrameActivex::GetContainingDocument(IHTMLDocument2** doc) {
ScopedComPtr<IOleContainer> container;
HRESULT hr = m_spClientSite->GetContainer(container.Receive());
if (container)
hr = container.QueryInterface(doc);
return hr;
}
HRESULT ChromeFrameActivex::GetDocumentWindow(IHTMLWindow2** window) {
ScopedComPtr<IHTMLDocument2> document;
HRESULT hr = GetContainingDocument(document.Receive());
if (document)
hr = document->get_parentWindow(window);
return hr;
}
void ChromeFrameActivex::OnLoad(int tab_handle, const GURL& gurl) {
ScopedComPtr<IDispatch> event;
std::string url = gurl.spec();
if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
Fire_onload(event);
FireEvent(onload_, url);
HRESULT hr = InvokeScriptFunction(onload_handler_, url);
if (ready_state_ < READYSTATE_COMPLETE) {
ready_state_ = READYSTATE_COMPLETE;
FireOnChanged(DISPID_READYSTATE);
}
}
void ChromeFrameActivex::OnLoadFailed(int error_code, const std::string& url) {
ScopedComPtr<IDispatch> event;
if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
Fire_onloaderror(event);
FireEvent(onloaderror_, url);
HRESULT hr = InvokeScriptFunction(onerror_handler_, url);
}
void ChromeFrameActivex::OnMessageFromChromeFrame(int tab_handle,
const std::string& message,
const std::string& origin,
const std::string& target) {
DLOG(INFO) << __FUNCTION__;
if (target.compare("*") != 0) {
bool drop = true;
if (is_privileged_) {
// Forward messages if the control is in privileged mode.
ScopedComPtr<IDispatch> message_event;
if (SUCCEEDED(CreateDomEvent("message", message, origin,
message_event.Receive()))) {
ScopedBstr target_bstr(UTF8ToWide(target).c_str());
Fire_onprivatemessage(message_event, target_bstr);
FireEvent(onprivatemessage_, message_event, target_bstr);
}
} else {
if (HaveSameOrigin(target, document_url_)) {
drop = false;
} else {
DLOG(WARNING) << "Dropping posted message since target doesn't match "
"the current document's origin. target=" << target;
}
}
if (drop)
return;
}
ScopedComPtr<IDispatch> message_event;
if (SUCCEEDED(CreateDomEvent("message", message, origin,
message_event.Receive()))) {
Fire_onmessage(message_event);
FireEvent(onmessage_, message_event);
ScopedVariant event_var;
event_var.Set(static_cast<IDispatch*>(message_event));
InvokeScriptFunction(onmessage_handler_, event_var.AsInput());
}
}
void ChromeFrameActivex::OnAutomationServerLaunchFailed(
AutomationLaunchResult reason, const std::string& server_version) {
Base::OnAutomationServerLaunchFailed(reason, server_version);
if (reason == AUTOMATION_VERSION_MISMATCH) {
DisplayVersionMismatchWarning(m_hWnd, server_version);
}
}
HRESULT ChromeFrameActivex::InvokeScriptFunction(const VARIANT& script_object,
const std::string& param) {
ScopedVariant script_arg(UTF8ToWide(param.c_str()).c_str());
return InvokeScriptFunction(script_object, script_arg.AsInput());
}
HRESULT ChromeFrameActivex::InvokeScriptFunction(const VARIANT& script_object,
VARIANT* param) {
if (V_VT(&script_object) != VT_DISPATCH) {
return S_FALSE;
}
CComPtr<IDispatch> script(script_object.pdispVal);
HRESULT hr = script.Invoke1(static_cast<DISPID>(DISPID_VALUE), param);
// 0x80020101 == SCRIPT_E_REPORTED.
// When the script we're invoking has an error, we get this error back.
DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101) << "Failed to invoke script";
return hr;
}
HRESULT ChromeFrameActivex::OnDraw(ATL_DRAWINFO& draw_info) { // NO_LINT
HRESULT hr = S_OK;
int dc_type = ::GetObjectType(draw_info.hicTargetDev);
if (dc_type == OBJ_ENHMETADC) {
RECT print_bounds = {0};
print_bounds.left = draw_info.prcBounds->left;
print_bounds.right = draw_info.prcBounds->right;
print_bounds.top = draw_info.prcBounds->top;
print_bounds.bottom = draw_info.prcBounds->bottom;
automation_client_->Print(draw_info.hdcDraw, print_bounds);
} else {
hr = Base::OnDraw(draw_info);
}
return hr;
}
STDMETHODIMP ChromeFrameActivex::Load(IPropertyBag* bag, IErrorLog* error_log) {
DCHECK(bag);
const wchar_t* event_props[] = {
(L"onload"),
(L"onloaderror"),
(L"onmessage"),
(L"onreadystatechanged"),
};
ScopedComPtr<IHTMLObjectElement> obj_element;
GetObjectElement(obj_element.Receive());
ScopedBstr object_id;
GetObjectScriptId(obj_element, object_id.Receive());
ScopedComPtr<IHTMLElement2> element;
element.QueryFrom(obj_element);
HRESULT hr = S_OK;
for (int i = 0; SUCCEEDED(hr) && i < arraysize(event_props); ++i) {
ScopedBstr prop(event_props[i]);
ScopedVariant value;
if (SUCCEEDED(bag->Read(prop, value.Receive(), error_log))) {
if (value.type() != VT_BSTR ||
FAILED(hr = CreateScriptBlockForEvent(element, object_id,
V_BSTR(&value), prop))) {
DLOG(ERROR) << "Failed to create script block for " << prop
<< StringPrintf(L"hr=0x%08X, vt=%i", hr, value.type());
} else {
DLOG(INFO) << "script block created for event " << prop <<
StringPrintf(" (0x%08X)", hr) << " connections: " <<
ProxyDIChromeFrameEvents<ChromeFrameActivex>::m_vec.GetSize();
}
} else {
DLOG(INFO) << "event property " << prop << " not in property bag";
}
}
ScopedVariant src;
if (SUCCEEDED(bag->Read(StackBstr(L"src"), src.Receive(), error_log))) {
if (src.type() == VT_BSTR) {
hr = put_src(V_BSTR(&src));
DCHECK(hr != E_UNEXPECTED);
}
}
ScopedVariant use_chrome_network;
if (SUCCEEDED(bag->Read(StackBstr(L"useChromeNetwork"),
use_chrome_network.Receive(), error_log))) {
VariantChangeType(use_chrome_network.AsInput(),
use_chrome_network.AsInput(),
0, VT_BOOL);
if (use_chrome_network.type() == VT_BOOL) {
hr = put_useChromeNetwork(V_BOOL(&use_chrome_network));
DCHECK(hr != E_UNEXPECTED);
}
}
DLOG_IF(ERROR, FAILED(hr))
<< StringPrintf("Failed to load property bag: 0x%08X", hr);
return hr;
}
const wchar_t g_activex_mixed_content_error[] = {
L"data:text/html,<html><body><b>ChromeFrame Security Error<br><br>"
L"Cannot navigate to HTTP url when document URL is HTTPS</body></html>"};
STDMETHODIMP ChromeFrameActivex::put_src(BSTR src) {
GURL document_url(GetDocumentUrl());
if (document_url.SchemeIsSecure()) {
GURL source_url(src);
if (!source_url.SchemeIsSecure()) {
Base::put_src(ScopedBstr(g_activex_mixed_content_error));
return E_ACCESSDENIED;
}
}
return Base::put_src(src);
}
HRESULT ChromeFrameActivex::IOleObject_SetClientSite(
IOleClientSite* client_site) {
HRESULT hr = Base::IOleObject_SetClientSite(client_site);
if (FAILED(hr) || !client_site) {
EventHandlers* handlers[] = {
&onmessage_,
&onloaderror_,
&onload_,
&onreadystatechanged_,
};
for (int i = 0; i < arraysize(handlers); ++i)
handlers[i]->clear();
// Drop privileged mode on uninitialization.
is_privileged_ = false;
} else {
ScopedComPtr<IHTMLDocument2> document;
GetContainingDocument(document.Receive());
if (document) {
ScopedBstr url;
if (SUCCEEDED(document->get_URL(url.Receive())))
WideToUTF8(url, url.Length(), &document_url_);
}
// Probe to see whether the host implements the privileged service.
ScopedComPtr<IChromeFramePrivileged> service;
HRESULT service_hr = DoQueryService(SID_ChromeFramePrivileged, client_site,
service.Receive());
if (SUCCEEDED(service_hr) && service) {
// Does the host want privileged mode?
boolean wants_privileged = false;
service_hr = service->GetWantsPrivileged(&wants_privileged);
if (SUCCEEDED(service_hr) && wants_privileged)
is_privileged_ = true;
}
std::wstring chrome_extra_arguments;
std::wstring profile_name(GetHostProcessName(false));
if (is_privileged_) {
// Does the host want to provide extra arguments?
ScopedBstr extra_arguments_arg;
service_hr = service->GetChromeExtraArguments(
extra_arguments_arg.Receive());
if (S_OK == service_hr && extra_arguments_arg)
chrome_extra_arguments.assign(extra_arguments_arg,
extra_arguments_arg.Length());
ScopedBstr profile_name_arg;
service_hr = service->GetChromeProfileName(profile_name_arg.Receive());
if (S_OK == service_hr && profile_name_arg)
profile_name.assign(profile_name_arg, profile_name_arg.Length());
}
if (!InitializeAutomation(profile_name, chrome_extra_arguments,
IsIEInPrivate())) {
return E_FAIL;
}
}
return hr;
}
HRESULT ChromeFrameActivex::GetObjectScriptId(IHTMLObjectElement* object_elem,
BSTR* id) {
DCHECK(object_elem != NULL);
DCHECK(id != NULL);
HRESULT hr = E_FAIL;
if (object_elem) {
ScopedComPtr<IHTMLElement> elem;
hr = elem.QueryFrom(object_elem);
if (elem) {
hr = elem->get_id(id);
}
}
return hr;
}
HRESULT ChromeFrameActivex::GetObjectElement(IHTMLObjectElement** element) {
DCHECK(m_spClientSite);
if (!m_spClientSite)
return E_UNEXPECTED;
ScopedComPtr<IOleControlSite> site;
HRESULT hr = site.QueryFrom(m_spClientSite);
if (site) {
ScopedComPtr<IDispatch> disp;
hr = site->GetExtendedControl(disp.Receive());
if (disp) {
hr = disp.QueryInterface(element);
} else {
DCHECK(FAILED(hr));
}
}
return hr;
}
HRESULT ChromeFrameActivex::CreateScriptBlockForEvent(
IHTMLElement2* insert_after, BSTR instance_id, BSTR script,
BSTR event_name) {
DCHECK(insert_after);
DCHECK(::SysStringLen(event_name) > 0); // should always have this
// This might be 0 if not specified in the HTML document.
if (!::SysStringLen(instance_id)) {
// TODO(tommi): Should we give ourselves an ID if this happens?
NOTREACHED() << "Need to handle this";
return E_INVALIDARG;
}
ScopedComPtr<IHTMLDocument2> document;
HRESULT hr = GetContainingDocument(document.Receive());
if (SUCCEEDED(hr)) {
ScopedComPtr<IHTMLElement> element, new_element;
document->createElement(StackBstr(L"script"), element.Receive());
if (element) {
ScopedComPtr<IHTMLScriptElement> script_element;
if (SUCCEEDED(hr = script_element.QueryFrom(element))) {
script_element->put_htmlFor(instance_id);
script_element->put_event(event_name);
script_element->put_text(script);
hr = insert_after->insertAdjacentElement(StackBstr(L"afterEnd"),
element,
new_element.Receive());
}
}
}
return hr;
}
HRESULT ChromeFrameActivex::CreateDomEvent(const std::string& event_type,
const std::string& data,
const std::string& origin,
IDispatch** event) {
DCHECK(event_type.length() > 0);
DCHECK(event != NULL);
CComObject<ComMessageEvent>* ev = NULL;
HRESULT hr = CComObject<ComMessageEvent>::CreateInstance(&ev);
if (SUCCEEDED(hr)) {
ev->AddRef();
ScopedComPtr<IOleContainer> container;
m_spClientSite->GetContainer(container.Receive());
if (ev->Initialize(container, data, origin, event_type)) {
*event = ev;
} else {
NOTREACHED() << "event->Initialize";
ev->Release();
hr = E_UNEXPECTED;
}
}
return hr;
}
void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
const std::string& arg) {
if (handlers.size()) {
ScopedComPtr<IDispatch> event;
if (SUCCEEDED(CreateDomEvent("event", arg, "", event.Receive()))) {
FireEvent(handlers, event);
}
}
}
void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
IDispatch* event) {
DCHECK(event != NULL);
VARIANT arg = { VT_DISPATCH };
arg.pdispVal = event;
DISPPARAMS params = { &arg, NULL, 1, 0 };
for (EventHandlers::const_iterator it = handlers.begin();
it != handlers.end();
++it) {
HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &params, NULL, NULL, NULL);
// 0x80020101 == SCRIPT_E_REPORTED.
// When the script we're invoking has an error, we get this error back.
DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
<< StringPrintf(L"Failed to invoke script: 0x%08X", hr);
}
}
void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
IDispatch* event, BSTR target) {
DCHECK(event != NULL);
// Arguments in reverse order to event handler function declaration,
// because that's what DISPPARAMS requires.
VARIANT args[2] = { { VT_BSTR }, { VT_DISPATCH }, };
args[0].bstrVal = target;
args[1].pdispVal = event;
DISPPARAMS params = { args, NULL, arraysize(args), 0 };
for (EventHandlers::const_iterator it = handlers.begin();
it != handlers.end();
++it) {
HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &params, NULL, NULL, NULL);
// 0x80020101 == SCRIPT_E_REPORTED.
// When the script we're invoking has an error, we get this error back.
DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
<< StringPrintf(L"Failed to invoke script: 0x%08X", hr);
}
}
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_FRAME_CHROME_FRAME_ACTIVEX_H_
#define CHROME_FRAME_CHROME_FRAME_ACTIVEX_H_
#include <atlbase.h>
#include <atlcom.h>
#include <atlctl.h>
#include <set>
#include <string>
#include "base/scoped_bstr_win.h"
#include "base/scoped_comptr_win.h"
#include "base/scoped_variant_win.h"
#include "chrome_frame/chrome_frame_activex_base.h"
#include "chrome_frame/com_type_info_holder.h"
#include "grit/chrome_frame_resources.h"
// Include without path to make GYP build see it.
#include "chrome_tab.h" // NOLINT
// ChromeFrameActivex: Implementation of the ActiveX control that is
// responsible for hosting a chrome frame, i.e. an iframe like widget which
// hosts the the chrome window. This object delegates to Chrome.exe
// (via the Chrome IPC-based automation mechanism) for the actual rendering.
class ATL_NO_VTABLE ChromeFrameActivex
: public ChromeFrameActivexBase<ChromeFrameActivex, CLSID_ChromeFrame>,
public IObjectSafetyImpl<ChromeFrameActivex,
INTERFACESAFE_FOR_UNTRUSTED_CALLER |
INTERFACESAFE_FOR_UNTRUSTED_DATA>,
public IPersistPropertyBag {
public:
typedef ChromeFrameActivexBase<ChromeFrameActivex, CLSID_ChromeFrame> Base;
ChromeFrameActivex();
~ChromeFrameActivex();
DECLARE_REGISTRY_RESOURCEID(IDR_CHROMEFRAME)
BEGIN_COM_MAP(ChromeFrameActivex)
COM_INTERFACE_ENTRY(IObjectSafety)
COM_INTERFACE_ENTRY(IPersistPropertyBag)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
COM_INTERFACE_ENTRY_CHAIN(Base)
END_COM_MAP()
BEGIN_MSG_MAP(ChromeFrameActivex)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
CHAIN_MSG_MAP(Base)
END_MSG_MAP()
HRESULT FinalConstruct();
virtual HRESULT OnDraw(ATL_DRAWINFO& draw_info);
// IPersistPropertyBag implementation
STDMETHOD(GetClassID)(CLSID* class_id) {
if (class_id != NULL)
*class_id = GetObjectCLSID();
return S_OK;
}
STDMETHOD(InitNew)() {
return S_OK;
}
STDMETHOD(Load)(IPropertyBag* bag, IErrorLog* error_log);
STDMETHOD(Save)(IPropertyBag* bag, BOOL clear_dirty, BOOL save_all) {
return E_NOTIMPL;
}
// Used to setup the document_url_ member needed for completing navigation.
// Create external tab (possibly in incognito mode).
HRESULT IOleObject_SetClientSite(IOleClientSite *pClientSite);
// Overridden to perform security checks.
STDMETHOD(put_src)(BSTR src);
protected:
virtual void OnAcceleratorPressed(int tab_handle, const MSG& accel_message);
virtual void OnLoad(int tab_handle, const GURL& url);
virtual void OnMessageFromChromeFrame(int tab_handle,
const std::string& message,
const std::string& origin,
const std::string& target);
private:
LRESULT OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
BOOL& handled); // NO_LINT
// ChromeFrameDelegate overrides
virtual void ChromeFrameActivex::OnAutomationServerLaunchFailed(
AutomationLaunchResult reason, const std::string& server_version);
virtual void OnLoadFailed(int error_code, const std::string& url);
// Helper function to execute a function on a script IDispatch interface.
HRESULT InvokeScriptFunction(const VARIANT& script, const std::string& param);
HRESULT InvokeScriptFunction(const VARIANT& script, VARIANT* param);
HRESULT GetContainingDocument(IHTMLDocument2** doc);
HRESULT GetDocumentWindow(IHTMLWindow2** window);
// Gets the value of the 'id' attribute of the object element.
HRESULT GetObjectScriptId(IHTMLObjectElement* object_elem, BSTR* id);
// Returns the object element in the HTML page.
// Note that if we're not being hosted inside an HTML
// document, then this call will fail.
HRESULT GetObjectElement(IHTMLObjectElement** element);
HRESULT CreateScriptBlockForEvent(IHTMLElement2* insert_after,
BSTR instance_id, BSTR script,
BSTR event_name);
// Creates a new event object that supports the |data| property.
// Note: you should supply an empty string for |origin| unless you're
// creating a "message" event.
HRESULT CreateDomEvent(const std::string& event_type, const std::string& data,
const std::string& origin, IDispatch** event);
// Utility function that checks the size of the vector and if > 0 creates
// a variant for the string argument and forwards the call to the other
// FireEvent method.
void FireEvent(const EventHandlers& handlers, const std::string& arg);
// Invokes all registered handlers in a vector of event handlers.
void FireEvent(const EventHandlers& handlers, IDispatch* event);
// This variant is used for the privatemessage handler only.
void FireEvent(const EventHandlers& handlers, IDispatch* event,
BSTR target);
};
OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex)
#endif // CHROME_FRAME_CHROME_FRAME_ACTIVEX_H_
HKLM {
NoRemove Software {
NoRemove Classes {
ChromeTab.ChromeFrame.1 = s 'Chrome Frame' {
CLSID = s '{E0A900DF-9611-4446-86BD-4B1D47E7DB2A}'
}
ChromeTab.ChromeFrame = s 'Chrome Frame' {
CLSID = s '{E0A900DF-9611-4446-86BD-4B1D47E7DB2A}'
CurVer = s 'ChromeTab.ChromeFrame.1'
}
NoRemove CLSID {
ForceRemove {E0A900DF-9611-4446-86BD-4B1D47E7DB2A} = s 'Chrome Frame' {
ProgID = s 'ChromeTab.ChromeFrame.1'
VersionIndependentProgID = s 'ChromeTab.ChromeFrame'
ForceRemove 'Programmable'
InprocServer32 = s '%MODULE%' {
val ThreadingModel = s 'Apartment'
}
val AppID = s '%APPID%'
ForceRemove 'Control'
ForceRemove 'Programmable'
ForceRemove 'Insertable'
ForceRemove 'ToolboxBitmap32' = s '%MODULE%, 1'
'MiscStatus' = s '0'
{
'1' = s '%OLEMISC%'
}
'TypeLib' = s '{6F2664E1-FF6E-488A-BCD1-F4CA6001DFCC}'
'Version' = s '1.0'
}
}
}
NoRemove Microsoft {
NoRemove Windows {
NoRemove CurrentVersion {
NoRemove Ext {
NoRemove PreApproved {
ForceRemove '{E0A900DF-9611-4446-86BD-4B1D47E7DB2A}' = s '' {
}
}
NoRemove Stats {
ForceRemove {E0A900DF-9611-4446-86BD-4B1D47E7DB2A} {
ForceRemove 'iexplore' {
val Type = d '1'
val Flags = d '4'
val Count = d '0'
val Time = b '%SYSTIME%'
ForceRemove AllowedDomains {
ForceRemove '*' {
}
}
}
}
}
}
}
}
NoRemove 'Internet Explorer' {
NoRemove 'Low Rights' {
NoRemove ElevationPolicy {
ForceRemove '{E0A900DF-9611-4446-86BD-4B1D47E7DB2A}' = s '' {
val Policy = d '3'
val AppName = s '%CHROME_LAUNCHER_APPNAME%'
val AppPath = s '%CHROME_LAUNCHER_APPPATH%'
}
}
NoRemove DragDrop {
ForceRemove '{E0A900DF-9611-4446-86BD-4B1D47E7DB2A}' = s '' {
val Policy = d '3'
val AppName = s '%CHROME_APPNAME%'
val AppPath = s '%CHROME_APPPATH%'
}
}
}
}
}
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome_frame/chrome_frame_delegate.h"
bool ChromeFrameDelegateImpl::IsTabMessage(const IPC::Message& message,
int* tab_handle) {
bool is_tab_message = true;
IPC_BEGIN_MESSAGE_MAP(ChromeFrameDelegateImpl, message)
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_NavigationStateChanged, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_UpdateTargetUrl, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_HandleAccelerator, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_TabbedOut, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_OpenURL, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_NavigationFailed, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_DidNavigate, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_TabLoaded, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_ForwardMessageToExternalHost, )
IPC_MESSAGE_HANDLER_GENERIC(
AutomationMsg_ForwardContextMenuToExternalHost, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_RequestStart, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_RequestRead, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_RequestEnd, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_SetCookieAsync, )
IPC_MESSAGE_HANDLER_GENERIC(AutomationMsg_AttachExternalTab, )
IPC_MESSAGE_UNHANDLED(is_tab_message = false);
IPC_END_MESSAGE_MAP()
if (is_tab_message) {
// Read tab handle from the message.
void* iter = NULL;
is_tab_message = message.ReadInt(&iter, tab_handle);
}
return is_tab_message;
}
void ChromeFrameDelegateImpl::OnMessageReceived(const IPC::Message& msg) {
if (!IsValid()) {
DLOG(WARNING) << __FUNCTION__
<< " Msgs received for a NULL automation client instance";
return;
}
IPC_BEGIN_MESSAGE_MAP(ChromeFrameDelegateImpl, msg)
IPC_MESSAGE_HANDLER(AutomationMsg_NavigationStateChanged,
OnNavigationStateChanged)
IPC_MESSAGE_HANDLER(AutomationMsg_UpdateTargetUrl, OnUpdateTargetUrl)
IPC_MESSAGE_HANDLER(AutomationMsg_HandleAccelerator,
OnAcceleratorPressed)
IPC_MESSAGE_HANDLER(AutomationMsg_TabbedOut, OnTabbedOut)
IPC_MESSAGE_HANDLER(AutomationMsg_OpenURL, OnOpenURL)
IPC_MESSAGE_HANDLER(AutomationMsg_NavigationFailed, OnNavigationFailed)
IPC_MESSAGE_HANDLER(AutomationMsg_DidNavigate, OnDidNavigate)
IPC_MESSAGE_HANDLER(AutomationMsg_TabLoaded, OnLoad)
IPC_MESSAGE_HANDLER(AutomationMsg_ForwardMessageToExternalHost,
OnMessageFromChromeFrame)
IPC_MESSAGE_HANDLER(AutomationMsg_ForwardContextMenuToExternalHost,
OnHandleContextMenu)
IPC_MESSAGE_HANDLER(AutomationMsg_RequestStart, OnRequestStart)
IPC_MESSAGE_HANDLER(AutomationMsg_RequestRead, OnRequestRead)
IPC_MESSAGE_HANDLER(AutomationMsg_RequestEnd, OnRequestEnd)
IPC_MESSAGE_HANDLER(AutomationMsg_SetCookieAsync, OnSetCookieAsync)
IPC_MESSAGE_HANDLER(AutomationMsg_AttachExternalTab, OnAttachExternalTab)
IPC_END_MESSAGE_MAP()
}
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_FRAME_CHROME_FRAME_DELEGATE_H_
#define CHROME_FRAME_CHROME_FRAME_DELEGATE_H_
#include "chrome/test/automation/automation_messages.h"
#include "ipc/ipc_message.h"
// A common interface supported by all the browser specific ChromeFrame
// implementations.
class ChromeFrameDelegate {
public:
typedef HWND WindowType;
virtual WindowType GetWindow() const = 0;
virtual void GetBounds(RECT* bounds) = 0;
virtual std::string GetDocumentUrl() = 0;
virtual void OnAutomationServerReady() = 0;
virtual void OnAutomationServerLaunchFailed(
AutomationLaunchResult reason, const std::string& server_version) = 0;
virtual void OnMessageReceived(const IPC::Message& msg) = 0;
// This remains in interface since we call it if Navigate()
// returns immediate error.
virtual void OnLoadFailed(int error_code, const std::string& url) = 0;
// Returns true if this instance is alive and well for processing automation
// messages.
virtual bool IsValid() const = 0;
protected:
~ChromeFrameDelegate() {}
};
// Template specialization
template <> struct RunnableMethodTraits<ChromeFrameDelegate> {
static void RetainCallee(ChromeFrameDelegate* obj) {
}
static void ReleaseCallee(ChromeFrameDelegate* obj) {
}
};
extern UINT kAutomationServerReady;
extern UINT kMessageFromChromeFrame;
class ChromeFrameDelegateImpl : public ChromeFrameDelegate {
public:
virtual WindowType GetWindow() { return NULL; }
virtual void GetBounds(RECT* bounds) {}
virtual std::string GetDocumentUrl() { return std::string(); }
virtual void OnAutomationServerReady() {}
virtual void OnAutomationServerLaunchFailed(
AutomationLaunchResult reason, const std::string& server_version) {}
virtual void OnLoadFailed(int error_code, const std::string& url) {}
virtual void OnMessageReceived(const IPC::Message& msg);
static bool IsTabMessage(const IPC::Message& message, int* tab_handle);
virtual bool IsValid() const {
return true;
}
protected:
// Protected methods to be overriden.
virtual void OnNavigationStateChanged(int tab_handle, int flags,
const IPC::NavigationInfo& nav_info) {}
virtual void OnUpdateTargetUrl(int tab_handle,
const std::wstring& new_target_url) {}
virtual void OnAcceleratorPressed(int tab_handle, const MSG& accel_message) {}
virtual void OnTabbedOut(int tab_handle, bool reverse) {}
virtual void OnOpenURL(int tab_handle, const GURL& url,
int open_disposition) {}
virtual void OnDidNavigate(int tab_handle,
const IPC::NavigationInfo& navigation_info) {}
virtual void OnNavigationFailed(int tab_handle, int error_code,
const GURL& gurl) {}
virtual void OnLoad(int tab_handle, const GURL& url) {}
virtual void OnMessageFromChromeFrame(int tab_handle,
const std::string& message,
const std::string& origin,
const std::string& target) {}
virtual void OnHandleContextMenu(int tab_handle, HANDLE menu_handle,
int x_pos, int y_pos, int align_flags) {}
virtual void OnRequestStart(int tab_handle, int request_id,
const IPC::AutomationURLRequest& request) {}
virtual void OnRequestRead(int tab_handle, int request_id,
int bytes_to_read) {}
virtual void OnRequestEnd(int tab_handle, int request_id,
const URLRequestStatus& status) {}
virtual void OnSetCookieAsync(int tab_handle, const GURL& url,
const std::string& cookie) {}
virtual void OnAttachExternalTab(int tab_handle, intptr_t cookie,
int disposition) {}
};
#endif // CHROME_FRAME_CHROME_FRAME_DELEGATE_H_
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome_frame/chrome_frame_histograms.h"
#include "base/histogram.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/pickle.h"
// Initialize histogram statistics gathering system.
base::LazyInstance<StatisticsRecorder>
g_statistics_recorder_(base::LINKER_INITIALIZED);
ChromeFrameHistogramSnapshots::ChromeFrameHistogramSnapshots() {
// Ensure that an instance of the StatisticsRecorder object is created.
g_statistics_recorder_.Get();
}
ChromeFrameHistogramSnapshots::HistogramPickledList
ChromeFrameHistogramSnapshots::GatherAllHistograms() {
StatisticsRecorder::Histograms histograms;
StatisticsRecorder::GetHistograms(&histograms);
HistogramPickledList pickled_histograms;
for (StatisticsRecorder::Histograms::iterator it = histograms.begin();
histograms.end() != it;
it++) {
GatherHistogram(**it, &pickled_histograms);
}
return pickled_histograms;
}
void ChromeFrameHistogramSnapshots::GatherHistogram(
const Histogram& histogram,
HistogramPickledList* pickled_histograms) {
// Get up-to-date snapshot of sample stats.
Histogram::SampleSet snapshot;
histogram.SnapshotSample(&snapshot);
const std::string& histogram_name = histogram.histogram_name();
// Check if we already have a log of this histogram and if not create an
// empty set.
LoggedSampleMap::iterator it = logged_samples_.find(histogram_name);
Histogram::SampleSet* already_logged;
if (logged_samples_.end() == it) {
// Add new entry.
already_logged = &logged_samples_[histogram.histogram_name()];
already_logged->Resize(histogram); // Complete initialization.
} else {
already_logged = &(it->second);
// Deduct any stats we've already logged from our snapshot.
snapshot.Subtract(*already_logged);
}
// Snapshot now contains only a delta to what we've already_logged.
if (snapshot.TotalCount() > 0) {
GatherHistogramDelta(histogram, snapshot, pickled_histograms);
// Add new data into our running total.
already_logged->Add(snapshot);
}
}
void ChromeFrameHistogramSnapshots::GatherHistogramDelta(
const Histogram& histogram,
const Histogram::SampleSet& snapshot,
HistogramPickledList* pickled_histograms) {
DCHECK(0 != snapshot.TotalCount());
snapshot.CheckSize(histogram);
std::string histogram_info =
Histogram::SerializeHistogramInfo(histogram, snapshot);
pickled_histograms->push_back(histogram_info);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment