Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(395)

Side by Side Diff: webkit/activex_shim/activex_plugin.cc

Issue 200031: Take out the activex control. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/activex_shim/activex_plugin.h ('k') | webkit/activex_shim/activex_shared.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2006-2008 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 #include "webkit/activex_shim/activex_plugin.h"
6
7 #include <algorithm>
8
9 #include "base/fix_wp64.h"
10 #include "base/scoped_comptr_win.h"
11 #include "base/string_util.h"
12 #include "googleurl/src/gurl.h"
13 #include "webkit/activex_shim/activex_shared.h"
14 #include "webkit/activex_shim/activex_util.h"
15 #include "webkit/activex_shim/npp_impl.h"
16 #include "webkit/activex_shim/npn_scripting.h"
17 #include "webkit/activex_shim/web_activex_site.h"
18
19 using std::string;
20 using std::wstring;
21
22 namespace activex_shim {
23
24 // Constant strings used in SetProp.
25 const wchar_t WNDPROP_ORIGINAL_WNDPROC[] = L"activexshim_orgwndproc";
26
27 ActiveXPlugin::ActiveXPlugin(NPP instance)
28 : DispatchObject(NULL),
29 npp_(instance),
30 container_(NULL),
31 windowless_(false),
32 tried_activation_(false),
33 control_activated_(false),
34 activex_type_(ACTIVEX_GENERIC) {
35 rect_.left = 0;
36 rect_.top = 0;
37 rect_.right = 0;
38 rect_.bottom = 0;
39 }
40
41 ActiveXPlugin::~ActiveXPlugin() {
42 // Releases all spawned Dispatch objects so that we won't have dangling
43 // references.
44 ReleaseSpawned();
45 }
46
47 // Firefox makes it pretty easy to distiguish between attrs and real params.
48 // it always places attrs first, then a pair with name "PARAM" and empty value.
49 // However, Chrome always put params first, then attrs. Need to figure out
50 // a way to handle them nicely.
51 void ActiveXPlugin::ProcessParams(int16 argc, char* argn[], char* argv[]) {
52 // TODO(ruijiang): This list is not exhaustive yet. Add all possible
53 // commmon attributes.
54 static const char* const excluded_param_names[] = {
55 "id", "name", "type", "class", "classid",
56 "codebase", "width", "height" };
57
58 // Handle parameters.
59 for (int i = 0; i < argc; i++) {
60 if (argn[i] == NULL)
61 continue;
62
63 ControlParam param;
64 param.name = UTF8ToWide(argn[i]);
65 // Sometimes browser will pass NULL when no value is present.
66 if (argv[i] != NULL) {
67 param.value = UTF8ToWide(argv[i]);
68 }
69 if (LowerCaseEqualsASCII(param.name, "classid")) {
70 std::string clsid_ascii;
71 if (GetClsidFromClassidAttribute(argv[i], &clsid_ascii)) {
72 std::wstring raw_clsid = UTF8ToWide(clsid_ascii);
73 clsid_ = wstring(L"{") + raw_clsid + L"}";
74 activex_type_ = MapClassIdToType(clsid_ascii);
75 }
76 }
77 if (LowerCaseEqualsASCII(param.name, "codebase")) {
78 codebase_ = param.value;
79 }
80 bool ignore = false;
81 for (int i = 0; i < arraysize(excluded_param_names); i++) {
82 if (LowerCaseEqualsASCII(param.name, excluded_param_names[i])) {
83 ignore = true;
84 break;
85 }
86 }
87 if (!ignore)
88 params_.push_back(param);
89 }
90 }
91
92 void ActiveXPlugin::ConvertForEmbeddedWmp() {
93 clsid_ = L"{6bf52a52-394a-11d3-b153-00c04f79faa6}";
94 ControlParam* existing_url_param = NULL;
95 std::wstring src;
96 // Find the src parameter and use it to add a new url parameter.
97 // Find the volume parameter and setup defaults which make sense in
98 // the Activex media player world.
99 for (unsigned int i = 0; i < params_.size(); i++) {
100 if (LowerCaseEqualsASCII(params_[i].name, "src")) {
101 src = params_[i].value;
102 } else if (LowerCaseEqualsASCII(params_[i].name, "url")) {
103 existing_url_param = &params_[i];
104 } else if (LowerCaseEqualsASCII(params_[i].name, "volume")) {
105 // In the NPAPI media player world a volume value lesser than
106 // -3000 turns off the volume. A volume value of 0 indicates
107 // full volume. Translate these to their Activex counterparts.
108 int specified_volume = 0;
109 if (StringToInt(params_[i].value, &specified_volume)) {
110 // Valid volume lies between 0 and -3000
111 specified_volume = std::min (0, std::max(-3000, specified_volume));
112 // Translate to a value between 0 and 100.
113 int activex_volume = specified_volume / 30 + 100;
114 params_[i].value = IntToWString(activex_volume);
115 }
116 }
117 }
118
119 if (!src.empty()) {
120 if (existing_url_param == NULL)
121 params_.push_back(ControlParam(L"url", src));
122 else
123 existing_url_param->value = src;
124 }
125 }
126
127 NPError ActiveXPlugin::NPP_New(NPMIMEType plugin_type, int16 argc, char* argn[],
128 char* argv[], NPSavedData* saved) {
129 ProcessParams(argc, argn, argv);
130
131 // If mimetype is not activex, it must be windows media type. Do necessary
132 // param conversion.
133 if (!IsMimeTypeActiveX(plugin_type))
134 ConvertForEmbeddedWmp();
135
136 DCHECK(container_ == NULL);
137 container_.reset(new NoRefIUnknownImpl<WebActiveXContainer>);
138 // At this time we don't know the browser window yet.
139 container_->Init(this);
140 HRESULT hr = container_->CreateControlWithSite(clsid_.c_str());
141 // TODO(ruijiang): We may still return OK, then show error inside the control
142 // so that user may get a chance to install it.
143 if (FAILED(hr))
144 return NPERR_GENERIC_ERROR;
145
146 // Does the control support windowless activation?
147 // TODO(ruijiang): temporary disable windowless plugin cause it's not fully
148 // working yet.
149 if (false && container_->GetFirstSite()->inplace_object_windowless_ != NULL) {
150 // TODO(ruijiang): Fix this. Right now Chrome will never return browser
151 // window when plugin hasn't set NPPVpluginWindowBool to false yet.
152 // Fix Chrome then we could remove this line.
153 g_browser->setvalue(npp_, NPPVpluginWindowBool, false);
154 // If we could get the container window successfully, we could go
155 // windowless.
156 HWND hwnd = NULL;
157 g_browser->getvalue(npp_, NPNVnetscapeWindow, &hwnd);
158 if (hwnd) {
159 container_->set_container_wnd(hwnd);
160 g_browser->setvalue(npp_, NPPVpluginWindowBool, false);
161 windowless_ = true;
162 } else {
163 g_browser->setvalue(npp_, NPPVpluginWindowBool,
164 reinterpret_cast<void*>(true));
165 }
166 }
167
168 // TODO(ruijiang): It is very common that controls query for the current url
169 // during activation. In the current Chrome multi-process structure this
170 // often causes deadlock (e.g. realplayer). Let's cache the url first while
171 // looking for ways to solve deadlock.
172 GetCurrentURL();
173 return 0;
174 }
175
176 void SubclassWindow(HWND hwnd, WNDPROC wndproc) {
177 LONG_PTR org_wndproc = SetWindowLongPtr(
178 hwnd, GWL_WNDPROC, reinterpret_cast<LONG_PTR>(wndproc));
179 SetProp(hwnd, WNDPROP_ORIGINAL_WNDPROC,
180 reinterpret_cast<HANDLE>(org_wndproc));
181 }
182
183 // Unsubclass a window that has been subclassed by us (has the property
184 // WNDPROP_ORIGINAL_WNDPROC)
185 void UnsubclassWindow(HWND hwnd) {
186 WNDPROC org_wndproc = static_cast<WNDPROC>(
187 GetProp(hwnd, WNDPROP_ORIGINAL_WNDPROC));
188 // Either this window has already been unsubclassed or it is not subclassed
189 // by us.
190 if (org_wndproc == NULL)
191 return;
192 SetWindowLongPtr(hwnd,
193 GWL_WNDPROC,
194 reinterpret_cast<LONG_PTR>(org_wndproc));
195 RemoveProp(hwnd, WNDPROP_ORIGINAL_WNDPROC);
196 }
197
198 // Window procedure to subclass Window created by control.
199 LRESULT CALLBACK ControlWindowProc(HWND hwnd, UINT msg,
200 WPARAM wparam, LPARAM lparam) {
201 WNDPROC org_wndproc = static_cast<WNDPROC>(
202 GetProp(hwnd, WNDPROP_ORIGINAL_WNDPROC));
203 switch(msg) {
204 case WM_KEYDOWN:
205 if (wparam == VK_TAB) {
206 // TODO(ruijiang): Handle the tab key to transfer focus back to browser.
207 // HWND hparent = GetParent(hwnd);
208 // HWND hparent2 = GetParent(hparent);
209 // PostMessage(hparent2, WM_KEYDOWN, wparam, lparam);
210 // return 0;
211 }
212 break;
213 case WM_DESTROY:
214 // Unsubclass myself.
215 UnsubclassWindow(hwnd);
216 break;
217 }
218 if (org_wndproc != NULL)
219 return CallWindowProc(org_wndproc, hwnd, msg, wparam, lparam);
220 else
221 return 0;
222 }
223
224 // NPP API Processing.
225 NPError ActiveXPlugin::NPP_SetWindow(NPWindow* window) {
226 if (window->type != NPWindowTypeWindow &&
227 window->type != NPWindowTypeDrawable)
228 return NPERR_GENERIC_ERROR;
229
230 // Remember the window position. This position is relative to the browser.
231 rect_.left = window->x;
232 rect_.top = window->y;
233 rect_.right = rect_.left + window->width;
234 rect_.bottom = rect_.top + window->height;
235
236 RECT client;
237 client.left = 0;
238 client.top = 0;
239 client.right = window->width;
240 client.bottom = window->height;
241
242 // This happens when we did not create the container because we do not
243 // allow initialization of certain ActiveX objects.
244 if (container_ == NULL)
245 return NPERR_GENERIC_ERROR;
246
247 if (!tried_activation_) {
248 // Do not try activation again.
249 tried_activation_ = true;
250
251 // For windowed controls we need to get the plugin window.
252 if (window->type == NPWindowTypeWindow)
253 container_->set_container_wnd(static_cast<HWND>(window->window));
254 WebActiveXSite* site = container_->GetFirstSite();
255 if (site == NULL)
256 return NPERR_GENERIC_ERROR;
257 POINT pos;
258 if (windowless()) {
259 pos.x = window->x;
260 pos.y = window->y;
261 } else {
262 pos.x = 0;
263 pos.y = 0;
264 }
265 HRESULT hr = site->ActivateControl(pos.x, pos.y, window->width,
266 window->height, params_);
267 if (FAILED(hr))
268 return NPERR_GENERIC_ERROR;
269
270 // We are done with activation.
271 control_activated_ = true;
272
273 if (window->type == NPWindowTypeWindow) {
274 HWND hwnd = static_cast<HWND>(window->window);
275 // The window some browser (FF) created does not clip children. It will
276 // cause blinking of the control area during resizing, clicking etc.
277 SetWindowLong(hwnd, GWL_STYLE,
278 GetWindowLong(hwnd, GWL_STYLE) | WS_CLIPCHILDREN |
279 WS_CLIPSIBLINGS);
280 // If the control has a window, we need to subclass it.
281 IUnknown* control = container_->GetFirstControl();
282 if (control) {
283 ScopedComPtr<IOleWindow> ole_window;
284 ole_window.QueryFrom(control);
285 if (ole_window != NULL) {
286 HWND control_wnd = NULL;
287 hr = ole_window->GetWindow(&control_wnd);
288 if (SUCCEEDED(hr)) {
289 SubclassWindow(control_wnd, ControlWindowProc);
290 }
291 }
292 }
293 }
294 return 0;
295 } else if (control_activated_) {
296 WebActiveXSite* site = container_->GetFirstSite();
297 DCHECK(site != NULL);
298 if (window->type == NPWindowTypeWindow) {
299 site->SetRect(&client);
300 } else {
301 site->SetRect(&rect_);
302 }
303 return 0;
304 } else {
305 return NPERR_GENERIC_ERROR;
306 }
307 }
308
309 NPError ActiveXPlugin::NPP_NewStream(NPMIMEType type, NPStream* stream,
310 NPBool seekable, uint16* stype) {
311 return 0;
312 }
313
314 NPError ActiveXPlugin::NPP_DestroyStream(NPStream* stream, NPReason reason) {
315 return 0;
316 }
317
318 int32 ActiveXPlugin::NPP_WriteReady(NPStream* stream) {
319 // TODO(ruijiang): Now returns an arbitary value. Will handle it later.
320 return 65536;
321 }
322
323 int32 ActiveXPlugin::NPP_Write(NPStream* stream, int32 offset, int32 len,
324 void* buffer) {
325 // TODO(ruijiang): Pretend we have processed it. Otherwise FireFox will
326 // pretty much deadlock.
327 return len;
328 }
329
330 void ActiveXPlugin::NPP_StreamAsFile(NPStream* stream, const char* fname) {
331 }
332
333 void ActiveXPlugin::NPP_Print(NPPrint* platformPrint) {
334 }
335
336 int16 ActiveXPlugin::NPP_HandleEvent(void* event) {
337 if (!control_activated_)
338 return NPERR_GENERIC_ERROR;
339
340 NPEvent* evt = static_cast<NPEvent*>(event);
341 // TODO(ruijiang): Handle various events here for windowless control.
342 switch (evt->event) {
343 case WM_PAINT:
344 return HandlePaintEvent(
345 reinterpret_cast<HDC>(static_cast<LONG_PTR>(evt->wParam)),
346 reinterpret_cast<NPRect*>(static_cast<LONG_PTR>(evt->lParam)));
347 case WM_LBUTTONDOWN:
348 case WM_MBUTTONDOWN:
349 case WM_RBUTTONDOWN:
350 case WM_LBUTTONUP:
351 case WM_MBUTTONUP:
352 case WM_RBUTTONUP:
353 case WM_LBUTTONDBLCLK:
354 case WM_MBUTTONDBLCLK:
355 case WM_RBUTTONDBLCLK:
356 case WM_MOUSEMOVE:
357 case WM_KEYUP:
358 case WM_KEYDOWN:
359 case WM_SETFOCUS:
360 return HandleInputEvent(evt->event, evt->wParam, evt->lParam);
361 case WM_SETCURSOR:
362 // TODO(ruijiang): seems we are not getting this message
363 break;
364 case WM_KILLFOCUS:
365 // TODO(ruijiang): We are not getting this message yet.
366 break;
367 default:
368 break;
369 }
370
371 return 0;
372 }
373
374 int16 ActiveXPlugin::HandlePaintEvent(HDC dc, NPRect* invalid_area) {
375 // Chrome sets world transform by a certain offset in some cases, e.g.,
376 // clicking on the control. This will cause unfortunate effect on ActiveX
377 // control, because some will try to adjust the drawing rect and reset the
378 // window/view point origin to 0. However, they are not aware of the new
379 // SetWolrTransform feature. Thus causing drawing off the real control area
380 // (see atlctl.h: CComControlBase::OnDrawAdvanced)
381 // On the other hand, FireFox never changes the origins. I've spent hours
382 // figuring out what went wrong...
383 int saved = SaveDC(dc);
384
385 POINT offset;
386 offset.x = offset.y = 0;
387 // Easy way to figure out the difference between world and device.
388 LPtoDP(dc, &offset, 1);
389 RECT rc = rect_;
390 OffsetRect(&rc, offset.x, offset.y);
391
392 // Reset everything so that device page has the same origin as the world.
393 SetWindowOrgEx(dc, 0, 0, NULL);
394 SetViewportOrgEx(dc, 0, 0, NULL);
395 if (GetGraphicsMode(dc) == GM_ADVANCED) {
396 XFORM f;
397 if (GetWorldTransform(dc, &f)) {
398 f.eDx = 0;
399 f.eDy = 0;
400 SetWorldTransform(dc, &f);
401 }
402 }
403
404 WebActiveXSite* site = container_->GetFirstSite();
405 if (site->view_object_ != NULL)
406 site->view_object_->Draw(DVASPECT_CONTENT, -1, NULL, NULL, NULL, dc,
407 reinterpret_cast<RECTL*>(&rc), NULL, NULL, 0);
408
409 RestoreDC(dc, saved);
410 return 0;
411 }
412
413 int16 ActiveXPlugin::HandleInputEvent(uint32 msg, uint32 wparam,
414 uint32 lparam) {
415 WebActiveXSite* site = container_->GetFirstSite();
416 if (site->inplace_object_windowless_ == NULL)
417 return 0;
418 LRESULT result;
419 HRESULT hr = site->inplace_object_windowless_->OnWindowMessage(
420 msg, wparam, lparam, &result);
421 return 0;
422 }
423
424 void ActiveXPlugin::NPP_URLNotify(const char* url, NPReason reason,
425 void* notifyData) {
426 }
427
428 NPError ActiveXPlugin::NPP_GetValue(NPPVariable variable, void* value) {
429 if (variable == NPPVpluginScriptableNPObject) {
430 *(static_cast<void**>(value)) = GetScriptableNPObject();
431 return 0;
432 }
433 return NPERR_GENERIC_ERROR;
434 }
435
436 NPError ActiveXPlugin::NPP_SetValue(NPNVariable variable, void* value) {
437 // No setable value yet.
438 return NPERR_GENERIC_ERROR;
439 }
440
441 void ActiveXPlugin::Draw(HDC dc, RECT* lprc, RECT* lpclip) {
442 // TODO(ruijiang): Temporary. Fix this later.
443 int ret = FillRect(dc, lprc,
444 static_cast<HBRUSH>(GetStockObject(DKGRAY_BRUSH)));
445 TextOut(dc, lprc->left, lprc->top, _T("HelloWorld"), 5);
446 }
447
448 IDispatch* ActiveXPlugin::GetDispatch() {
449 if (container_ == NULL || container_->GetFirstControl() == NULL)
450 return NULL;
451 ScopedComPtr<IDispatch> disp;
452 disp.QueryFrom(container_->GetFirstControl());
453 if (!disp)
454 return NULL;
455 IDispatch* res = disp.Detach();
456 res->Release();
457 return res;
458 }
459
460 NPNScriptableObject ActiveXPlugin::GetWindow() {
461 if (!window_.IsValid()) {
462 NPObject* object = NULL;
463 g_browser->getvalue(npp_, NPNVWindowNPObject, &object);
464 window_ = NPNScriptableObject(npp_, object);
465 }
466 return window_;
467 }
468
469 std::wstring ActiveXPlugin::GetCurrentURL() {
470 if (url_.size())
471 return url_;
472 url_ = GetWindow().GetObjectProperty("document").GetStringProperty("URL");
473 return url_;
474 }
475
476 std::wstring ActiveXPlugin::ResolveURL(const std::wstring& url) {
477 // TODO(ruijiang): consider the base element of document.
478 std::wstring doc_url = GetCurrentURL();
479 GURL base(doc_url);
480 GURL ret = base.Resolve(url);
481 return UTF8ToWide(ret.spec());
482 }
483
484
485 } // namespace activex_shim
OLDNEW
« no previous file with comments | « webkit/activex_shim/activex_plugin.h ('k') | webkit/activex_shim/activex_shared.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698