Index: webkit/activex_shim/activex_plugin.cc |
=================================================================== |
--- webkit/activex_shim/activex_plugin.cc (revision 25626) |
+++ webkit/activex_shim/activex_plugin.cc (working copy) |
@@ -1,485 +0,0 @@ |
-// Copyright (c) 2006-2008 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 "webkit/activex_shim/activex_plugin.h" |
- |
-#include <algorithm> |
- |
-#include "base/fix_wp64.h" |
-#include "base/scoped_comptr_win.h" |
-#include "base/string_util.h" |
-#include "googleurl/src/gurl.h" |
-#include "webkit/activex_shim/activex_shared.h" |
-#include "webkit/activex_shim/activex_util.h" |
-#include "webkit/activex_shim/npp_impl.h" |
-#include "webkit/activex_shim/npn_scripting.h" |
-#include "webkit/activex_shim/web_activex_site.h" |
- |
-using std::string; |
-using std::wstring; |
- |
-namespace activex_shim { |
- |
-// Constant strings used in SetProp. |
-const wchar_t WNDPROP_ORIGINAL_WNDPROC[] = L"activexshim_orgwndproc"; |
- |
-ActiveXPlugin::ActiveXPlugin(NPP instance) |
- : DispatchObject(NULL), |
- npp_(instance), |
- container_(NULL), |
- windowless_(false), |
- tried_activation_(false), |
- control_activated_(false), |
- activex_type_(ACTIVEX_GENERIC) { |
- rect_.left = 0; |
- rect_.top = 0; |
- rect_.right = 0; |
- rect_.bottom = 0; |
-} |
- |
-ActiveXPlugin::~ActiveXPlugin() { |
- // Releases all spawned Dispatch objects so that we won't have dangling |
- // references. |
- ReleaseSpawned(); |
-} |
- |
-// Firefox makes it pretty easy to distiguish between attrs and real params. |
-// it always places attrs first, then a pair with name "PARAM" and empty value. |
-// However, Chrome always put params first, then attrs. Need to figure out |
-// a way to handle them nicely. |
-void ActiveXPlugin::ProcessParams(int16 argc, char* argn[], char* argv[]) { |
- // TODO(ruijiang): This list is not exhaustive yet. Add all possible |
- // commmon attributes. |
- static const char* const excluded_param_names[] = { |
- "id", "name", "type", "class", "classid", |
- "codebase", "width", "height" }; |
- |
- // Handle parameters. |
- for (int i = 0; i < argc; i++) { |
- if (argn[i] == NULL) |
- continue; |
- |
- ControlParam param; |
- param.name = UTF8ToWide(argn[i]); |
- // Sometimes browser will pass NULL when no value is present. |
- if (argv[i] != NULL) { |
- param.value = UTF8ToWide(argv[i]); |
- } |
- if (LowerCaseEqualsASCII(param.name, "classid")) { |
- std::string clsid_ascii; |
- if (GetClsidFromClassidAttribute(argv[i], &clsid_ascii)) { |
- std::wstring raw_clsid = UTF8ToWide(clsid_ascii); |
- clsid_ = wstring(L"{") + raw_clsid + L"}"; |
- activex_type_ = MapClassIdToType(clsid_ascii); |
- } |
- } |
- if (LowerCaseEqualsASCII(param.name, "codebase")) { |
- codebase_ = param.value; |
- } |
- bool ignore = false; |
- for (int i = 0; i < arraysize(excluded_param_names); i++) { |
- if (LowerCaseEqualsASCII(param.name, excluded_param_names[i])) { |
- ignore = true; |
- break; |
- } |
- } |
- if (!ignore) |
- params_.push_back(param); |
- } |
-} |
- |
-void ActiveXPlugin::ConvertForEmbeddedWmp() { |
- clsid_ = L"{6bf52a52-394a-11d3-b153-00c04f79faa6}"; |
- ControlParam* existing_url_param = NULL; |
- std::wstring src; |
- // Find the src parameter and use it to add a new url parameter. |
- // Find the volume parameter and setup defaults which make sense in |
- // the Activex media player world. |
- for (unsigned int i = 0; i < params_.size(); i++) { |
- if (LowerCaseEqualsASCII(params_[i].name, "src")) { |
- src = params_[i].value; |
- } else if (LowerCaseEqualsASCII(params_[i].name, "url")) { |
- existing_url_param = ¶ms_[i]; |
- } else if (LowerCaseEqualsASCII(params_[i].name, "volume")) { |
- // In the NPAPI media player world a volume value lesser than |
- // -3000 turns off the volume. A volume value of 0 indicates |
- // full volume. Translate these to their Activex counterparts. |
- int specified_volume = 0; |
- if (StringToInt(params_[i].value, &specified_volume)) { |
- // Valid volume lies between 0 and -3000 |
- specified_volume = std::min (0, std::max(-3000, specified_volume)); |
- // Translate to a value between 0 and 100. |
- int activex_volume = specified_volume / 30 + 100; |
- params_[i].value = IntToWString(activex_volume); |
- } |
- } |
- } |
- |
- if (!src.empty()) { |
- if (existing_url_param == NULL) |
- params_.push_back(ControlParam(L"url", src)); |
- else |
- existing_url_param->value = src; |
- } |
-} |
- |
-NPError ActiveXPlugin::NPP_New(NPMIMEType plugin_type, int16 argc, char* argn[], |
- char* argv[], NPSavedData* saved) { |
- ProcessParams(argc, argn, argv); |
- |
- // If mimetype is not activex, it must be windows media type. Do necessary |
- // param conversion. |
- if (!IsMimeTypeActiveX(plugin_type)) |
- ConvertForEmbeddedWmp(); |
- |
- DCHECK(container_ == NULL); |
- container_.reset(new NoRefIUnknownImpl<WebActiveXContainer>); |
- // At this time we don't know the browser window yet. |
- container_->Init(this); |
- HRESULT hr = container_->CreateControlWithSite(clsid_.c_str()); |
- // TODO(ruijiang): We may still return OK, then show error inside the control |
- // so that user may get a chance to install it. |
- if (FAILED(hr)) |
- return NPERR_GENERIC_ERROR; |
- |
- // Does the control support windowless activation? |
- // TODO(ruijiang): temporary disable windowless plugin cause it's not fully |
- // working yet. |
- if (false && container_->GetFirstSite()->inplace_object_windowless_ != NULL) { |
- // TODO(ruijiang): Fix this. Right now Chrome will never return browser |
- // window when plugin hasn't set NPPVpluginWindowBool to false yet. |
- // Fix Chrome then we could remove this line. |
- g_browser->setvalue(npp_, NPPVpluginWindowBool, false); |
- // If we could get the container window successfully, we could go |
- // windowless. |
- HWND hwnd = NULL; |
- g_browser->getvalue(npp_, NPNVnetscapeWindow, &hwnd); |
- if (hwnd) { |
- container_->set_container_wnd(hwnd); |
- g_browser->setvalue(npp_, NPPVpluginWindowBool, false); |
- windowless_ = true; |
- } else { |
- g_browser->setvalue(npp_, NPPVpluginWindowBool, |
- reinterpret_cast<void*>(true)); |
- } |
- } |
- |
- // TODO(ruijiang): It is very common that controls query for the current url |
- // during activation. In the current Chrome multi-process structure this |
- // often causes deadlock (e.g. realplayer). Let's cache the url first while |
- // looking for ways to solve deadlock. |
- GetCurrentURL(); |
- return 0; |
-} |
- |
-void SubclassWindow(HWND hwnd, WNDPROC wndproc) { |
- LONG_PTR org_wndproc = SetWindowLongPtr( |
- hwnd, GWL_WNDPROC, reinterpret_cast<LONG_PTR>(wndproc)); |
- SetProp(hwnd, WNDPROP_ORIGINAL_WNDPROC, |
- reinterpret_cast<HANDLE>(org_wndproc)); |
-} |
- |
-// Unsubclass a window that has been subclassed by us (has the property |
-// WNDPROP_ORIGINAL_WNDPROC) |
-void UnsubclassWindow(HWND hwnd) { |
- WNDPROC org_wndproc = static_cast<WNDPROC>( |
- GetProp(hwnd, WNDPROP_ORIGINAL_WNDPROC)); |
- // Either this window has already been unsubclassed or it is not subclassed |
- // by us. |
- if (org_wndproc == NULL) |
- return; |
- SetWindowLongPtr(hwnd, |
- GWL_WNDPROC, |
- reinterpret_cast<LONG_PTR>(org_wndproc)); |
- RemoveProp(hwnd, WNDPROP_ORIGINAL_WNDPROC); |
-} |
- |
-// Window procedure to subclass Window created by control. |
-LRESULT CALLBACK ControlWindowProc(HWND hwnd, UINT msg, |
- WPARAM wparam, LPARAM lparam) { |
- WNDPROC org_wndproc = static_cast<WNDPROC>( |
- GetProp(hwnd, WNDPROP_ORIGINAL_WNDPROC)); |
- switch(msg) { |
- case WM_KEYDOWN: |
- if (wparam == VK_TAB) { |
- // TODO(ruijiang): Handle the tab key to transfer focus back to browser. |
- // HWND hparent = GetParent(hwnd); |
- // HWND hparent2 = GetParent(hparent); |
- // PostMessage(hparent2, WM_KEYDOWN, wparam, lparam); |
- // return 0; |
- } |
- break; |
- case WM_DESTROY: |
- // Unsubclass myself. |
- UnsubclassWindow(hwnd); |
- break; |
- } |
- if (org_wndproc != NULL) |
- return CallWindowProc(org_wndproc, hwnd, msg, wparam, lparam); |
- else |
- return 0; |
-} |
- |
-// NPP API Processing. |
-NPError ActiveXPlugin::NPP_SetWindow(NPWindow* window) { |
- if (window->type != NPWindowTypeWindow && |
- window->type != NPWindowTypeDrawable) |
- return NPERR_GENERIC_ERROR; |
- |
- // Remember the window position. This position is relative to the browser. |
- rect_.left = window->x; |
- rect_.top = window->y; |
- rect_.right = rect_.left + window->width; |
- rect_.bottom = rect_.top + window->height; |
- |
- RECT client; |
- client.left = 0; |
- client.top = 0; |
- client.right = window->width; |
- client.bottom = window->height; |
- |
- // This happens when we did not create the container because we do not |
- // allow initialization of certain ActiveX objects. |
- if (container_ == NULL) |
- return NPERR_GENERIC_ERROR; |
- |
- if (!tried_activation_) { |
- // Do not try activation again. |
- tried_activation_ = true; |
- |
- // For windowed controls we need to get the plugin window. |
- if (window->type == NPWindowTypeWindow) |
- container_->set_container_wnd(static_cast<HWND>(window->window)); |
- WebActiveXSite* site = container_->GetFirstSite(); |
- if (site == NULL) |
- return NPERR_GENERIC_ERROR; |
- POINT pos; |
- if (windowless()) { |
- pos.x = window->x; |
- pos.y = window->y; |
- } else { |
- pos.x = 0; |
- pos.y = 0; |
- } |
- HRESULT hr = site->ActivateControl(pos.x, pos.y, window->width, |
- window->height, params_); |
- if (FAILED(hr)) |
- return NPERR_GENERIC_ERROR; |
- |
- // We are done with activation. |
- control_activated_ = true; |
- |
- if (window->type == NPWindowTypeWindow) { |
- HWND hwnd = static_cast<HWND>(window->window); |
- // The window some browser (FF) created does not clip children. It will |
- // cause blinking of the control area during resizing, clicking etc. |
- SetWindowLong(hwnd, GWL_STYLE, |
- GetWindowLong(hwnd, GWL_STYLE) | WS_CLIPCHILDREN | |
- WS_CLIPSIBLINGS); |
- // If the control has a window, we need to subclass it. |
- IUnknown* control = container_->GetFirstControl(); |
- if (control) { |
- ScopedComPtr<IOleWindow> ole_window; |
- ole_window.QueryFrom(control); |
- if (ole_window != NULL) { |
- HWND control_wnd = NULL; |
- hr = ole_window->GetWindow(&control_wnd); |
- if (SUCCEEDED(hr)) { |
- SubclassWindow(control_wnd, ControlWindowProc); |
- } |
- } |
- } |
- } |
- return 0; |
- } else if (control_activated_) { |
- WebActiveXSite* site = container_->GetFirstSite(); |
- DCHECK(site != NULL); |
- if (window->type == NPWindowTypeWindow) { |
- site->SetRect(&client); |
- } else { |
- site->SetRect(&rect_); |
- } |
- return 0; |
- } else { |
- return NPERR_GENERIC_ERROR; |
- } |
-} |
- |
-NPError ActiveXPlugin::NPP_NewStream(NPMIMEType type, NPStream* stream, |
- NPBool seekable, uint16* stype) { |
- return 0; |
-} |
- |
-NPError ActiveXPlugin::NPP_DestroyStream(NPStream* stream, NPReason reason) { |
- return 0; |
-} |
- |
-int32 ActiveXPlugin::NPP_WriteReady(NPStream* stream) { |
- // TODO(ruijiang): Now returns an arbitary value. Will handle it later. |
- return 65536; |
-} |
- |
-int32 ActiveXPlugin::NPP_Write(NPStream* stream, int32 offset, int32 len, |
- void* buffer) { |
- // TODO(ruijiang): Pretend we have processed it. Otherwise FireFox will |
- // pretty much deadlock. |
- return len; |
-} |
- |
-void ActiveXPlugin::NPP_StreamAsFile(NPStream* stream, const char* fname) { |
-} |
- |
-void ActiveXPlugin::NPP_Print(NPPrint* platformPrint) { |
-} |
- |
-int16 ActiveXPlugin::NPP_HandleEvent(void* event) { |
- if (!control_activated_) |
- return NPERR_GENERIC_ERROR; |
- |
- NPEvent* evt = static_cast<NPEvent*>(event); |
- // TODO(ruijiang): Handle various events here for windowless control. |
- switch (evt->event) { |
- case WM_PAINT: |
- return HandlePaintEvent( |
- reinterpret_cast<HDC>(static_cast<LONG_PTR>(evt->wParam)), |
- reinterpret_cast<NPRect*>(static_cast<LONG_PTR>(evt->lParam))); |
- case WM_LBUTTONDOWN: |
- case WM_MBUTTONDOWN: |
- case WM_RBUTTONDOWN: |
- case WM_LBUTTONUP: |
- case WM_MBUTTONUP: |
- case WM_RBUTTONUP: |
- case WM_LBUTTONDBLCLK: |
- case WM_MBUTTONDBLCLK: |
- case WM_RBUTTONDBLCLK: |
- case WM_MOUSEMOVE: |
- case WM_KEYUP: |
- case WM_KEYDOWN: |
- case WM_SETFOCUS: |
- return HandleInputEvent(evt->event, evt->wParam, evt->lParam); |
- case WM_SETCURSOR: |
- // TODO(ruijiang): seems we are not getting this message |
- break; |
- case WM_KILLFOCUS: |
- // TODO(ruijiang): We are not getting this message yet. |
- break; |
- default: |
- break; |
- } |
- |
- return 0; |
-} |
- |
-int16 ActiveXPlugin::HandlePaintEvent(HDC dc, NPRect* invalid_area) { |
- // Chrome sets world transform by a certain offset in some cases, e.g., |
- // clicking on the control. This will cause unfortunate effect on ActiveX |
- // control, because some will try to adjust the drawing rect and reset the |
- // window/view point origin to 0. However, they are not aware of the new |
- // SetWolrTransform feature. Thus causing drawing off the real control area |
- // (see atlctl.h: CComControlBase::OnDrawAdvanced) |
- // On the other hand, FireFox never changes the origins. I've spent hours |
- // figuring out what went wrong... |
- int saved = SaveDC(dc); |
- |
- POINT offset; |
- offset.x = offset.y = 0; |
- // Easy way to figure out the difference between world and device. |
- LPtoDP(dc, &offset, 1); |
- RECT rc = rect_; |
- OffsetRect(&rc, offset.x, offset.y); |
- |
- // Reset everything so that device page has the same origin as the world. |
- SetWindowOrgEx(dc, 0, 0, NULL); |
- SetViewportOrgEx(dc, 0, 0, NULL); |
- if (GetGraphicsMode(dc) == GM_ADVANCED) { |
- XFORM f; |
- if (GetWorldTransform(dc, &f)) { |
- f.eDx = 0; |
- f.eDy = 0; |
- SetWorldTransform(dc, &f); |
- } |
- } |
- |
- WebActiveXSite* site = container_->GetFirstSite(); |
- if (site->view_object_ != NULL) |
- site->view_object_->Draw(DVASPECT_CONTENT, -1, NULL, NULL, NULL, dc, |
- reinterpret_cast<RECTL*>(&rc), NULL, NULL, 0); |
- |
- RestoreDC(dc, saved); |
- return 0; |
-} |
- |
-int16 ActiveXPlugin::HandleInputEvent(uint32 msg, uint32 wparam, |
- uint32 lparam) { |
- WebActiveXSite* site = container_->GetFirstSite(); |
- if (site->inplace_object_windowless_ == NULL) |
- return 0; |
- LRESULT result; |
- HRESULT hr = site->inplace_object_windowless_->OnWindowMessage( |
- msg, wparam, lparam, &result); |
- return 0; |
-} |
- |
-void ActiveXPlugin::NPP_URLNotify(const char* url, NPReason reason, |
- void* notifyData) { |
-} |
- |
-NPError ActiveXPlugin::NPP_GetValue(NPPVariable variable, void* value) { |
- if (variable == NPPVpluginScriptableNPObject) { |
- *(static_cast<void**>(value)) = GetScriptableNPObject(); |
- return 0; |
- } |
- return NPERR_GENERIC_ERROR; |
-} |
- |
-NPError ActiveXPlugin::NPP_SetValue(NPNVariable variable, void* value) { |
- // No setable value yet. |
- return NPERR_GENERIC_ERROR; |
-} |
- |
-void ActiveXPlugin::Draw(HDC dc, RECT* lprc, RECT* lpclip) { |
- // TODO(ruijiang): Temporary. Fix this later. |
- int ret = FillRect(dc, lprc, |
- static_cast<HBRUSH>(GetStockObject(DKGRAY_BRUSH))); |
- TextOut(dc, lprc->left, lprc->top, _T("HelloWorld"), 5); |
-} |
- |
-IDispatch* ActiveXPlugin::GetDispatch() { |
- if (container_ == NULL || container_->GetFirstControl() == NULL) |
- return NULL; |
- ScopedComPtr<IDispatch> disp; |
- disp.QueryFrom(container_->GetFirstControl()); |
- if (!disp) |
- return NULL; |
- IDispatch* res = disp.Detach(); |
- res->Release(); |
- return res; |
-} |
- |
-NPNScriptableObject ActiveXPlugin::GetWindow() { |
- if (!window_.IsValid()) { |
- NPObject* object = NULL; |
- g_browser->getvalue(npp_, NPNVWindowNPObject, &object); |
- window_ = NPNScriptableObject(npp_, object); |
- } |
- return window_; |
-} |
- |
-std::wstring ActiveXPlugin::GetCurrentURL() { |
- if (url_.size()) |
- return url_; |
- url_ = GetWindow().GetObjectProperty("document").GetStringProperty("URL"); |
- return url_; |
-} |
- |
-std::wstring ActiveXPlugin::ResolveURL(const std::wstring& url) { |
- // TODO(ruijiang): consider the base element of document. |
- std::wstring doc_url = GetCurrentURL(); |
- GURL base(doc_url); |
- GURL ret = base.Resolve(url); |
- return UTF8ToWide(ret.spec()); |
-} |
- |
- |
-} // namespace activex_shim |