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

Side by Side Diff: chrome_frame/chrome_frame_npapi.cc

Issue 7276037: Remove NPAPI support from Chrome Frame. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 5 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 | « chrome_frame/chrome_frame_npapi.h ('k') | chrome_frame/chrome_frame_npapi_entrypoints.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) 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 #include "chrome_frame/chrome_frame_npapi.h"
6
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/message_loop.h"
10 #include "base/string_split.h"
11 #include "base/string_util.h"
12 #include "base/stringprintf.h"
13 #include "base/utf_string_conversions.h"
14 #include "chrome/test/automation/tab_proxy.h"
15 #include "chrome_frame/np_utils.h"
16 #include "chrome_frame/utils.h"
17
18 MessageLoop* ChromeFrameNPAPI::message_loop_ = NULL;
19 int ChromeFrameNPAPI::instance_count_ = 0;
20
21 NPClass ChromeFrameNPAPI::plugin_class_ = {
22 NP_CLASS_STRUCT_VERSION,
23 ChromeFrameNPAPI::AllocateObject,
24 ChromeFrameNPAPI::DeallocateObject,
25 ChromeFrameNPAPI::Invalidate,
26 ChromeFrameNPAPI::HasMethod,
27 ChromeFrameNPAPI::Invoke,
28 NULL, // invokeDefault
29 ChromeFrameNPAPI::HasProperty,
30 ChromeFrameNPAPI::GetProperty,
31 ChromeFrameNPAPI::SetProperty,
32 NULL, // remove property
33 NULL, // enumeration
34 NULL, // construct
35 };
36
37 NPIdentifier
38 ChromeFrameNPAPI::plugin_property_identifiers_[PLUGIN_PROPERTY_COUNT]
39 = {0};
40
41 const NPUTF8* ChromeFrameNPAPI::plugin_property_identifier_names_[] = {
42 "version",
43 "src",
44 "onload",
45 "onloaderror",
46 "onmessage",
47 "readystate",
48 "usechromenetwork",
49 "onclose",
50 };
51
52 const NPUTF8* ChromeFrameNPAPI::plugin_method_identifier_names_[] = {
53 "postMessage",
54 };
55
56 ChromeFrameNPAPI::PluginMethod ChromeFrameNPAPI::plugin_methods_[] = {
57 &ChromeFrameNPAPI::postMessage,
58 };
59
60 NPIdentifier
61 ChromeFrameNPAPI::plugin_method_identifiers_[arraysize(plugin_methods_)]
62 = {0};
63
64
65 void ChromeFrameNPAPI::CompileAsserts() {
66 NOTREACHED(); // This function should never be invoked.
67
68 COMPILE_ASSERT(arraysize(plugin_method_identifier_names_) ==
69 arraysize(plugin_methods_),
70 you_must_add_both_plugin_method_and_name);
71
72 COMPILE_ASSERT(arraysize(plugin_property_identifier_names_) ==
73 arraysize(plugin_property_identifiers_),
74 you_must_add_both_plugin_property_and_name);
75 }
76
77 static const char kPluginSrcAttribute[] = "src";
78 static const char kPluginForceFullPageAttribute[] = "force_full_page";
79 static const char kPluginOnloadAttribute[] = "onload";
80 static const char kPluginOnErrorAttribute[] = "onloaderror";
81 static const char kPluginOnMessageAttribute[] = "onmessage";
82 static const char kPluginOnPrivateMessageAttribute[] = "onprivatemessage";
83 static const char kPluginOnCloseAttribute[] = "onclose";
84
85 // If chrome network stack is to be used
86 static const char kPluginUseChromeNetwork[] = "usechromenetwork";
87
88 // ChromeFrameNPAPI member defines.
89
90 // TODO(tommi): remove ignore_setfocus_ since that's not how focus is
91 // handled anymore.
92
93 ChromeFrameNPAPI::ChromeFrameNPAPI()
94 : instance_(NULL),
95 mode_(NP_EMBED),
96 force_full_page_plugin_(false),
97 ready_state_(READYSTATE_LOADING),
98 enabled_popups_(false),
99 navigate_after_initialization_(false) {
100 }
101
102 ChromeFrameNPAPI::~ChromeFrameNPAPI() {
103 if (IsWindow()) {
104 if (!UnsubclassWindow()) {
105 // TODO(tommi): Figure out why this can sometimes happen in the
106 // WidgetModeFF_Resize unittest.
107 DLOG(ERROR) << "Couldn't unsubclass safely!";
108 UnsubclassWindow(TRUE);
109 }
110 }
111 m_hWnd = NULL;
112
113 instance_count_--;
114 if (instance_count_ <= 0) {
115 delete message_loop_;
116 message_loop_ = NULL;
117 }
118
119 Uninitialize();
120 }
121
122 std::string ChromeFrameNPAPI::GetLocation() {
123 // Note that GetWindowObject() will cache the window object here.
124 return np_utils::GetLocation(instance_, GetWindowObject());
125 }
126
127 bool ChromeFrameNPAPI::Initialize(NPMIMEType mime_type, NPP instance,
128 uint16 mode, int16 argc, char* argn[],
129 char* argv[]) {
130 if (!Base::Initialize())
131 return false;
132
133 instance_ = instance;
134 mime_type_ = mime_type;
135 mode_ = mode;
136 document_url_ = GetLocation();
137
138 if (instance_count_ == 0) {
139 DCHECK(message_loop_ == NULL);
140 message_loop_ = new MessageLoop();
141 }
142
143 instance_count_++;
144
145 for (int i = 0; i < argc; ++i) {
146 if (LowerCaseEqualsASCII(argn[i], kPluginSrcAttribute)) {
147 src_ = ResolveURL(GetDocumentUrl(), argv[i]);
148 } else if (LowerCaseEqualsASCII(argn[i], kPluginForceFullPageAttribute)) {
149 force_full_page_plugin_ = atoi(argv[i]) ? true : false;
150 } else if (LowerCaseEqualsASCII(argn[i], kPluginOnErrorAttribute)) {
151 onerror_handler_ = JavascriptToNPObject(argv[i]);
152 } else if (LowerCaseEqualsASCII(argn[i], kPluginOnMessageAttribute)) {
153 onmessage_handler_ = JavascriptToNPObject(argv[i]);
154 } else if (LowerCaseEqualsASCII(argn[i], kPluginOnCloseAttribute)) {
155 onclose_handler_ = JavascriptToNPObject(argv[i]);
156 }
157 }
158
159 std::wstring profile_name(GetHostProcessName(false));
160 std::wstring extra_arguments;
161
162 static const wchar_t kHandleTopLevelRequests[] = L"HandleTopLevelRequests";
163 bool top_level_requests = GetConfigBool(true, kHandleTopLevelRequests);
164 automation_client_->set_handle_top_level_requests(top_level_requests);
165 automation_client_->set_route_all_top_level_navigations(true);
166
167 // Setup Url fetcher.
168 url_fetcher_.set_NPPInstance(instance_);
169 url_fetcher_.set_frame_busting(!is_privileged());
170 automation_client_->SetUrlFetcher(&url_fetcher_);
171
172 // TODO(joshia): Initialize navigation here and send proxy config as
173 // part of LaunchSettings
174 /*
175 if (!src_.empty())
176 automation_client_->InitiateNavigation(src_, is_privileged());
177
178 std::string proxy_settings;
179 bool has_prefs = pref_service_->Initialize(instance_,
180 automation_client_.get());
181 if (has_prefs && pref_service_->GetProxyValueJSONString(&proxy_settings)) {
182 automation_client_->SetProxySettings(proxy_settings);
183 }
184 */
185
186 // We can't call SubscribeToFocusEvents here since
187 // when Initialize gets called, Opera is in a state where
188 // it can't handle calls back and the thread will hang.
189 // Instead, we call SubscribeToFocusEvents when we initialize
190 // our plugin window.
191
192 // TODO(stoyan): Ask host for specific interface whether to honor
193 // host's in-private mode.
194 return InitializeAutomation(profile_name, extra_arguments,
195 GetBrowserIncognitoMode(), true,
196 GURL(src_), GURL(), true);
197 }
198
199 void ChromeFrameNPAPI::Uninitialize() {
200 if (ready_state_ != READYSTATE_UNINITIALIZED)
201 SetReadyState(READYSTATE_UNINITIALIZED);
202
203 window_object_.Free();
204 onerror_handler_.Free();
205 onmessage_handler_.Free();
206 onprivatemessage_handler_.Free();
207 onclose_handler_.Free();
208
209 Base::Uninitialize();
210 }
211
212 void ChromeFrameNPAPI::OnFinalMessage(HWND window) {
213 // The automation server should be gone by now.
214 Uninitialize();
215 }
216
217 bool ChromeFrameNPAPI::SetWindow(NPWindow* window_info) {
218 if (!window_info || !automation_client_.get()) {
219 NOTREACHED();
220 return false;
221 }
222
223 HWND window = reinterpret_cast<HWND>(window_info->window);
224 if (!::IsWindow(window)) {
225 // No window created yet. Ignore this call.
226 return false;
227 }
228
229 if (IsWindow()) {
230 // We've already subclassed, make sure that SetWindow doesn't get called
231 // with an HWND other than the one we subclassed during our lifetime.
232 DCHECK(window == m_hWnd);
233 return true;
234 }
235
236 automation_client_->SetParentWindow(window);
237
238 if (force_full_page_plugin_) {
239 // By default full page mode is only enabled when the plugin is loaded off
240 // a separate file, i.e. it is the primary content in the window. Even if
241 // we specify the width/height attributes for the plugin as 100% each, FF
242 // instantiates the plugin passing in a width/height of 100px each. To
243 // workaround this we resize the plugin window passed in by FF to the size
244 // of its parent.
245 HWND plugin_parent_window = ::GetParent(window);
246 RECT plugin_parent_rect = {0};
247 ::GetClientRect(plugin_parent_window, &plugin_parent_rect);
248 ::SetWindowPos(window, NULL, plugin_parent_rect.left,
249 plugin_parent_rect.top,
250 plugin_parent_rect.right - plugin_parent_rect.left,
251 plugin_parent_rect.bottom - plugin_parent_rect.top, 0);
252 }
253
254 // Subclass the browser's plugin window here.
255 if (SubclassWindow(window)) {
256 DWORD new_style_flags = WS_CLIPCHILDREN;
257 ModifyStyle(0, new_style_flags, 0);
258
259 if (ready_state_ < READYSTATE_INTERACTIVE) {
260 SetReadyState(READYSTATE_INTERACTIVE);
261 }
262 }
263
264 return true;
265 }
266
267 void ChromeFrameNPAPI::Print(NPPrint* print_info) {
268 if (!print_info) {
269 NOTREACHED();
270 return;
271 }
272
273 // We dont support full tab mode yet.
274 if (print_info->mode != NP_EMBED) {
275 NOTREACHED();
276 return;
277 }
278
279 NPWindow window = print_info->print.embedPrint.window;
280
281 RECT print_bounds = {0};
282 print_bounds.left = window.x;
283 print_bounds.top = window.y;
284 print_bounds.right = window.x + window.width;
285 print_bounds.bottom = window.x + window.height;
286
287 automation_client_->Print(
288 reinterpret_cast<HDC>(print_info->print.embedPrint.platformPrint),
289 print_bounds);
290 }
291
292 void ChromeFrameNPAPI::UrlNotify(const char* url, NPReason reason,
293 void* notify_data) {
294 if (enabled_popups_) {
295 // We have opened the URL so tell the browser to restore popup settings
296 enabled_popups_ = false;
297 npapi::PopPopupsEnabledState(instance_);
298 }
299
300 url_fetcher_.UrlNotify(url, reason, notify_data);
301 }
302
303 void ChromeFrameNPAPI::OnAcceleratorPressed(const MSG& accel_message) {
304 DVLOG(1) << __FUNCTION__
305 << " msg:" << base::StringPrintf("0x%04X", accel_message.message)
306 << " key:" << accel_message.wParam;
307
308 // The host browser does call TranslateMessage on messages like WM_KEYDOWN
309 // WM_KEYUP, etc, which will result in messages like WM_CHAR, WM_SYSCHAR, etc
310 // being posted to the message queue. We don't post these messages here to
311 // avoid these messages from getting handled twice.
312 if (accel_message.message != WM_CHAR &&
313 accel_message.message != WM_DEADCHAR &&
314 accel_message.message != WM_SYSCHAR &&
315 accel_message.message != WM_SYSDEADCHAR) {
316 // A very primitive way to handle keystrokes.
317 // TODO(tommi): When we've implemented a way for chrome to
318 // know when keystrokes are handled (deterministically) on that side,
319 // then this function should get called and not otherwise.
320 ::PostMessage(::GetParent(m_hWnd), accel_message.message,
321 accel_message.wParam, accel_message.lParam);
322 }
323
324 if (automation_client_.get()) {
325 TabProxy* tab = automation_client_->tab();
326 if (tab) {
327 tab->ProcessUnhandledAccelerator(accel_message);
328 }
329 }
330 }
331
332 void ChromeFrameNPAPI::OnTabbedOut(bool reverse) {
333 DVLOG(1) << __FUNCTION__;
334
335 ignore_setfocus_ = true;
336
337 // Previously we set the focus to our parent window before sending the
338 // keyboard event but the browser architecture has changed, so we release
339 // our focus first by calling <object>.blur() and then tabbing to the
340 // next element.
341 ScopedNpObject<NPObject> object;
342 npapi::GetValue(instance_, NPNVPluginElementNPObject, object.Receive());
343 if (object.get()) {
344 ScopedNpVariant result;
345 bool invoke = npapi::Invoke(instance_, object,
346 npapi::GetStringIdentifier("blur"), NULL, 0, &result);
347 DLOG_IF(WARNING, !invoke) << "blur failed";
348 } else {
349 DLOG(WARNING) << "Failed to get the plugin element";
350 }
351
352 INPUT input = {0};
353 input.type = INPUT_KEYBOARD;
354 input.ki.wVk = VK_TAB;
355 SendInput(1, &input, sizeof(input));
356 input.ki.dwFlags = KEYEVENTF_KEYUP;
357 SendInput(1, &input, sizeof(input));
358
359 ignore_setfocus_ = false;
360 }
361
362 void ChromeFrameNPAPI::OnOpenURL(const GURL& url,
363 const GURL& referrer,
364 int open_disposition) {
365 std::string target;
366 switch (open_disposition) {
367 case NEW_FOREGROUND_TAB:
368 target = "_blank";
369 break;
370 case NEW_BACKGROUND_TAB:
371 target = "_blank";
372 break;
373 case NEW_WINDOW:
374 case NEW_POPUP:
375 target = "_new";
376 break;
377 default:
378 break;
379 }
380
381 // Tell the browser to temporarily allow popups
382 enabled_popups_ = true;
383 npapi::PushPopupsEnabledState(instance_, TRUE);
384 npapi::GetURLNotify(instance_, url.spec().c_str(), target.c_str(), NULL);
385 }
386
387 bool ChromeFrameNPAPI::HasMethod(NPObject* obj, NPIdentifier name) {
388 for (int i = 0; i < arraysize(plugin_methods_); ++i) {
389 if (name == plugin_method_identifiers_[i])
390 return true;
391 }
392
393 DLOG(INFO) << "Do not have method: " << npapi::StringFromIdentifier(name);
394
395 return false;
396 }
397
398 bool ChromeFrameNPAPI::Invoke(NPObject* header, NPIdentifier name,
399 const NPVariant* args, uint32_t arg_count,
400 NPVariant* result) {
401 ChromeFrameNPAPI* plugin_instance = ChromeFrameInstanceFromNPObject(header);
402 if (!plugin_instance || !plugin_instance->automation_client_.get())
403 return false;
404
405 bool success = false;
406 for (int i = 0; i < arraysize(plugin_methods_); ++i) {
407 if (name == plugin_method_identifiers_[i]) {
408 PluginMethod method = plugin_methods_[i];
409 success = (plugin_instance->*method)(header, args, arg_count, result);
410 break;
411 }
412 }
413
414 return success;
415 }
416
417 void ChromeFrameNPAPI::InitializeIdentifiers() {
418 npapi::GetStringIdentifiers(plugin_method_identifier_names_,
419 arraysize(plugin_methods_),
420 plugin_method_identifiers_);
421
422 npapi::GetStringIdentifiers(plugin_property_identifier_names_,
423 PLUGIN_PROPERTY_COUNT,
424 plugin_property_identifiers_);
425 }
426
427 NPObject* ChromeFrameNPAPI::AllocateObject(NPP instance, NPClass* class_name) {
428 static bool identifiers_initialized = false;
429
430 ChromeFrameNPObject* plugin_object = new ChromeFrameNPObject();
431 DCHECK(plugin_object != NULL);
432
433 plugin_object->chrome_frame_plugin_instance = new ChromeFrameNPAPI();
434 DCHECK(plugin_object->chrome_frame_plugin_instance != NULL);
435
436 plugin_object->npp = NULL;
437
438 COMPILE_ASSERT(arraysize(plugin_method_identifiers_) ==
439 arraysize(plugin_method_identifier_names_),
440 method_count_mismatch);
441
442 COMPILE_ASSERT(arraysize(plugin_method_identifiers_) ==
443 arraysize(plugin_methods_),
444 method_count_mismatch);
445
446 if (!identifiers_initialized) {
447 InitializeIdentifiers();
448 identifiers_initialized = true;
449 }
450
451 return reinterpret_cast<NPObject*>(plugin_object);
452 }
453
454 void ChromeFrameNPAPI::DeallocateObject(NPObject* header) {
455 ChromeFrameNPObject* plugin_object =
456 reinterpret_cast<ChromeFrameNPObject*>(header);
457 DCHECK(plugin_object != NULL);
458
459 if (plugin_object) {
460 delete plugin_object->chrome_frame_plugin_instance;
461 delete plugin_object;
462 }
463 }
464
465 void ChromeFrameNPAPI::Invalidate(NPObject* header) {
466 DCHECK(header);
467 ChromeFrameNPObject* plugin_object =
468 reinterpret_cast<ChromeFrameNPObject*>(header);
469 if (plugin_object) {
470 DCHECK(plugin_object->chrome_frame_plugin_instance);
471 plugin_object->chrome_frame_plugin_instance->Uninitialize();
472 }
473 }
474
475 ChromeFrameNPAPI* ChromeFrameNPAPI::ChromeFrameInstanceFromPluginInstance(
476 NPP instance) {
477 if ((instance == NULL) || (instance->pdata == NULL)) {
478 NOTREACHED();
479 return NULL;
480 }
481
482 return ChromeFrameInstanceFromNPObject(instance->pdata);
483 }
484
485 ChromeFrameNPAPI* ChromeFrameNPAPI::ChromeFrameInstanceFromNPObject(
486 void* object) {
487 ChromeFrameNPObject* plugin_object =
488 reinterpret_cast<ChromeFrameNPObject*>(object);
489 if (!plugin_object) {
490 NOTREACHED();
491 return NULL;
492 }
493
494 DCHECK(plugin_object->chrome_frame_plugin_instance);
495 return plugin_object->chrome_frame_plugin_instance;
496 }
497
498 bool ChromeFrameNPAPI::HasProperty(NPObject* obj, NPIdentifier name) {
499 for (int i = 0; i < PLUGIN_PROPERTY_COUNT; ++i) {
500 if (name == plugin_property_identifiers_[i])
501 return true;
502 }
503 return false;
504 }
505
506 bool ChromeFrameNPAPI::GetProperty(NPIdentifier name,
507 NPVariant* variant) {
508 if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_ONERROR]) {
509 if (onerror_handler_) {
510 variant->type = NPVariantType_Object;
511 variant->value.objectValue = onerror_handler_.Copy();
512 return true;
513 }
514 } else if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_ONMESSAGE]) {
515 if (onmessage_handler_) {
516 variant->type = NPVariantType_Object;
517 variant->value.objectValue = onmessage_handler_.Copy();
518 return true;
519 }
520 } else if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_ONCLOSE]) {
521 if (onclose_handler_) {
522 variant->type = NPVariantType_Object;
523 variant->value.objectValue = onclose_handler_.Copy();
524 return true;
525 }
526 } else if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_SRC]) {
527 AllocateStringVariant(src_, variant);
528 return true;
529 } else if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_VERSION]) {
530 const std::wstring version =
531 automation_client_->GetVersion();
532 AllocateStringVariant(WideToUTF8(version), variant);
533 return true;
534 } else if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_READYSTATE]) {
535 INT32_TO_NPVARIANT(ready_state_, *variant);
536 return true;
537 } else if (name ==
538 plugin_property_identifiers_[PLUGIN_PROPERTY_USECHROMENETWORK]) {
539 BOOLEAN_TO_NPVARIANT(automation_client_->use_chrome_network(), *variant);
540 return true;
541 }
542
543 return false;
544 }
545
546 bool ChromeFrameNPAPI::GetProperty(NPObject* object, NPIdentifier name,
547 NPVariant* variant) {
548 if (!object || !variant) {
549 NOTREACHED();
550 return false;
551 }
552
553 ChromeFrameNPAPI* plugin_instance = ChromeFrameInstanceFromNPObject(object);
554 if (!plugin_instance) {
555 NOTREACHED();
556 return false;
557 }
558
559 return plugin_instance->GetProperty(name, variant);
560 }
561
562 bool ChromeFrameNPAPI::SetProperty(NPIdentifier name,
563 const NPVariant* variant) {
564 if (NPVARIANT_IS_OBJECT(*variant)) {
565 if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_ONERROR]) {
566 onerror_handler_.Free();
567 onerror_handler_ = variant->value.objectValue;
568 return true;
569 } else if (
570 name == plugin_property_identifiers_[PLUGIN_PROPERTY_ONMESSAGE]) {
571 onmessage_handler_.Free();
572 onmessage_handler_ = variant->value.objectValue;
573 return true;
574 } else if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_ONCLOSE]) {
575 onclose_handler_.Free();
576 onclose_handler_ = variant->value.objectValue;
577 return true;
578 }
579 } else if (NPVARIANT_IS_STRING(*variant) || NPVARIANT_IS_NULL(*variant)) {
580 if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_SRC]) {
581 return NavigateToURL(variant, 1, NULL);
582 }
583 } else if (NPVARIANT_IS_BOOLEAN(*variant)) {
584 if (name ==
585 plugin_property_identifiers_[PLUGIN_PROPERTY_USECHROMENETWORK]) {
586 automation_client_->set_use_chrome_network(
587 NPVARIANT_TO_BOOLEAN(*variant));
588 }
589 }
590
591 return false;
592 }
593
594 bool ChromeFrameNPAPI::SetProperty(NPObject* object, NPIdentifier name,
595 const NPVariant* variant) {
596 if (!object || !variant) {
597 DLOG(ERROR) << "Cannot set property: " << npapi::StringFromIdentifier(name);
598 return false;
599 }
600
601 ChromeFrameNPAPI* plugin_instance = ChromeFrameInstanceFromNPObject(object);
602 if (!plugin_instance) {
603 NOTREACHED();
604 return false;
605 }
606
607 return plugin_instance->SetProperty(name, variant);
608 }
609
610 LRESULT CALLBACK ChromeFrameNPAPI::DropKillFocusHook(int code, WPARAM wparam,
611 LPARAM lparam) {
612 LRESULT ret = 0;
613 CWPSTRUCT* wp = reinterpret_cast<CWPSTRUCT*>(lparam);
614 if ((code < 0) || (wp->message != WM_KILLFOCUS))
615 ret = ::CallNextHookEx(NULL, code, wparam, lparam);
616
617 return ret;
618 }
619
620 LRESULT ChromeFrameNPAPI::OnSetFocus(UINT message, WPARAM wparam,
621 LPARAM lparam, BOOL& handled) { // NO_LINT
622 // Opera has a WH_CALLWNDPROC hook that handles WM_KILLFOCUS and
623 // prevents us from setting the focus to the tab.
624 // To work around that, we set a temporary hook here that does nothing
625 // (not even call other hooks) when it sees WM_KILLFOCUS.
626 HHOOK hook = NULL;
627 hook = ::SetWindowsHookEx(WH_CALLWNDPROC, DropKillFocusHook, NULL,
628 ::GetCurrentThreadId());
629 // Since we chain message maps, make sure we are not calling base class
630 // twice for WM_SETFOCUS.
631 BOOL handled_by_base = TRUE;
632 LRESULT ret = Base::OnSetFocus(message, wparam, lparam, handled_by_base);
633 if (hook)
634 ::UnhookWindowsHookEx(hook);
635
636 return ret;
637 }
638
639 void ChromeFrameNPAPI::OnLoad(const GURL& gurl) {
640 DVLOG(1) << "Firing onload";
641 FireEvent("load", gurl.spec());
642 }
643
644 void ChromeFrameNPAPI::OnLoadFailed(int error_code, const std::string& url) {
645 FireEvent("loaderror", url);
646
647 ScopedNpVariant result;
648 InvokeDefault(onerror_handler_, url, &result);
649 }
650
651 void ChromeFrameNPAPI::OnMessageFromChromeFrame(const std::string& message,
652 const std::string& origin,
653 const std::string& target) {
654 bool private_message = false;
655 if (target.compare("*") != 0) {
656 if (is_privileged()) {
657 private_message = true;
658 } else {
659 if (!HaveSameOrigin(target, document_url_)) {
660 DLOG(WARNING) << "Dropping posted message since target doesn't match "
661 "the current document's origin. target=" << target;
662 return;
663 }
664 }
665 }
666
667 // Create a MessageEvent object that contains the message and origin
668 // as well as supporting other MessageEvent (see the HTML5 spec) properties.
669 // Then call the onmessage handler.
670 ScopedNpObject<NPObject> event;
671 bool ok = CreateMessageEvent(false, true, message, origin, event.Receive());
672 if (ok) {
673 // Don't call FireEvent here (or we'll have an event wrapped by an event).
674 DispatchEvent(event);
675
676 ScopedNpVariant result;
677 NPVariant params[2];
678 OBJECT_TO_NPVARIANT(event, params[0]);
679 bool invoke = false;
680 if (private_message) {
681 DCHECK(is_privileged());
682 STRINGN_TO_NPVARIANT(target.c_str(), target.length(), params[1]);
683 invoke = InvokeDefault(onprivatemessage_handler_,
684 arraysize(params),
685 params,
686 &result);
687 } else {
688 invoke = InvokeDefault(onmessage_handler_, params[0], &result);
689 }
690 DLOG_IF(WARNING, !invoke) << "InvokeDefault failed";
691 } else {
692 DLOG(WARNING) << "CreateMessageEvent failed, probably exiting";
693 }
694 }
695
696 void ChromeFrameNPAPI::OnAutomationServerReady() {
697 Base::OnAutomationServerReady();
698
699 if (navigate_after_initialization_ && !src_.empty()) {
700 navigate_after_initialization_ = false;
701 if (!automation_client_->InitiateNavigation(src_,
702 GetDocumentUrl(),
703 this)) {
704 DLOG(ERROR) << "Failed to navigate to: " << src_;
705 src_.clear();
706 }
707 }
708
709 SetReadyState(READYSTATE_COMPLETE);
710 }
711
712 void ChromeFrameNPAPI::OnAutomationServerLaunchFailed(
713 AutomationLaunchResult reason, const std::string& server_version) {
714 SetReadyState(READYSTATE_UNINITIALIZED);
715
716 // In IE, we don't display warnings for privileged CF instances because
717 // there are 2 CFs created for each tab (so we decide on the CEEE side
718 // whether to show a warning). In FF however, there is only one privileged
719 // CF instance per Firefox window, so OK to show the warning there without
720 // any further logic.
721 if (reason == AUTOMATION_VERSION_MISMATCH) {
722 UMA_HISTOGRAM_COUNTS("ChromeFrame.VersionMismatchDisplayed", 1);
723 DisplayVersionMismatchWarning(m_hWnd, server_version);
724 }
725 }
726
727 void ChromeFrameNPAPI::OnCloseTab() {
728 std::string arg;
729 FireEvent("close", arg);
730 ScopedNpVariant result;
731 InvokeDefault(onclose_handler_, arg, &result);
732 }
733
734 bool ChromeFrameNPAPI::InvokeDefault(NPObject* object,
735 unsigned param_count,
736 const NPVariant* params,
737 NPVariant* result) {
738 if (!object)
739 return false;
740
741 bool ret = npapi::InvokeDefault(instance_, object, params, param_count,
742 result);
743 // InvokeDefault can return false in FF even though we do see the call
744 // go through. It's not clear to me what the circumstances are, so
745 // we log it as a warning while tracking it down.
746 DLOG_IF(WARNING, !ret) << "npapi::InvokeDefault failed";
747 return ret;
748 }
749
750 bool ChromeFrameNPAPI::InvokeDefault(NPObject* object, const std::string& param,
751 NPVariant* result) {
752 NPVariant arg;
753 STRINGN_TO_NPVARIANT(param.c_str(), param.length(), arg);
754 return InvokeDefault(object, arg, result);
755 }
756
757 bool ChromeFrameNPAPI::InvokeDefault(NPObject* object, const NPVariant& param,
758 NPVariant* result) {
759 return InvokeDefault(object, 1, &param, result);
760 }
761
762 bool ChromeFrameNPAPI::CreateEvent(const std::string& type, bool bubbles,
763 bool cancelable, NPObject** basic_event) {
764 DCHECK(basic_event);
765 NPObject* window = GetWindowObject();
766 if (!window) {
767 // Can fail if the browser is closing (seen in Opera).
768 return false;
769 }
770
771 const char* identifier_names[] = {
772 "document",
773 "createEvent",
774 "initEvent",
775 };
776
777 NPIdentifier identifiers[arraysize(identifier_names)];
778 npapi::GetStringIdentifiers(identifier_names, arraysize(identifier_names),
779 identifiers);
780
781 // Fetch the document object from the window.
782 ScopedNpVariant document;
783 bool ok = npapi::GetProperty(instance_, window, identifiers[0], &document);
784 if (!ok) {
785 // This could happen if the page is being unloaded.
786 DLOG(WARNING) << "Failed to fetch the document object";
787 return false;
788 }
789
790 bool success = false;
791 if (ok && NPVARIANT_IS_OBJECT(document)) {
792 // Call document.createEvent("Event") to create a basic event object.
793 NPVariant event_type;
794 STRINGN_TO_NPVARIANT("Event", sizeof("Event") - 1, event_type);
795 ScopedNpVariant result;
796 success = npapi::Invoke(instance_, NPVARIANT_TO_OBJECT(document),
797 identifiers[1], &event_type, 1, &result);
798 if (!NPVARIANT_IS_OBJECT(result)) {
799 DLOG(WARNING) << "Failed to invoke createEvent";
800 success = false;
801 } else {
802 NPVariant init_args[3];
803 STRINGN_TO_NPVARIANT(type.c_str(), type.length(), init_args[0]);
804 BOOLEAN_TO_NPVARIANT(bubbles, init_args[1]);
805 BOOLEAN_TO_NPVARIANT(cancelable, init_args[2]);
806
807 // Now initialize the event object by calling
808 // event.initEvent(type, bubbles, cancelable);
809 ScopedNpVariant init_results;
810 ok = npapi::Invoke(instance_, NPVARIANT_TO_OBJECT(result), identifiers[2],
811 init_args, arraysize(init_args), &init_results);
812 if (ok) {
813 success = true;
814 // Finally, pass the ownership to the caller.
815 *basic_event = NPVARIANT_TO_OBJECT(result);
816 VOID_TO_NPVARIANT(result); // Prevent the object from being released.
817 } else {
818 DLOG(ERROR) << "initEvent failed";
819 success = false;
820 }
821 }
822 }
823
824 return success;
825 }
826
827 bool ChromeFrameNPAPI::CreateMessageEvent(bool bubbles, bool cancelable,
828 const std::string& data,
829 const std::string& origin,
830 NPObject** message_event) {
831 DCHECK(message_event);
832 ScopedNpObject<NPObject> event;
833 bool ok = CreateEvent("message", false, true, event.Receive());
834 if (ok) {
835 typedef enum {
836 DATA,
837 ORIGIN,
838 LAST_EVENT_ID,
839 SOURCE,
840 MESSAGE_PORT,
841 IDENTIFIER_COUNT, // Must be last.
842 } StringIdentifiers;
843
844 static NPIdentifier identifiers[IDENTIFIER_COUNT] = {0};
845 if (!identifiers[0]) {
846 const NPUTF8* identifier_names[] = {
847 "data",
848 "origin",
849 "lastEventId",
850 "source",
851 "messagePort",
852 };
853 COMPILE_ASSERT(arraysize(identifier_names) == arraysize(identifiers),
854 mismatched_array_size);
855 npapi::GetStringIdentifiers(identifier_names, IDENTIFIER_COUNT,
856 identifiers);
857 }
858
859 NPVariant arg;
860 STRINGN_TO_NPVARIANT(data.c_str(), data.length(), arg);
861 npapi::SetProperty(instance_, event, identifiers[DATA], &arg);
862 STRINGN_TO_NPVARIANT(origin.c_str(), origin.length(), arg);
863 npapi::SetProperty(instance_, event, identifiers[ORIGIN], &arg);
864 STRINGN_TO_NPVARIANT("", 0, arg);
865 npapi::SetProperty(instance_, event, identifiers[LAST_EVENT_ID], &arg);
866 NULL_TO_NPVARIANT(arg);
867 npapi::SetProperty(instance_, event, identifiers[SOURCE], &arg);
868 npapi::SetProperty(instance_, event, identifiers[MESSAGE_PORT], &arg);
869 *message_event = event.Detach();
870 }
871
872 return ok;
873 }
874
875
876 void ChromeFrameNPAPI::DispatchEvent(NPObject* event) {
877 DCHECK(event != NULL);
878
879 ScopedNpObject<NPObject> embed;
880 npapi::GetValue(instance_, NPNVPluginElementNPObject, &embed);
881 if (embed != NULL) {
882 NPVariant param;
883 OBJECT_TO_NPVARIANT(event, param);
884 ScopedNpVariant result;
885 bool invoke = npapi::Invoke(instance_, embed,
886 npapi::GetStringIdentifier("dispatchEvent"), &param, 1, &result);
887 DLOG_IF(WARNING, !invoke) << "dispatchEvent failed";
888 } else {
889 DLOG(WARNING) << "ChromeFrameNPAPI::DispatchEvent failed, probably exiting";
890 }
891 }
892
893 bool ChromeFrameNPAPI::ExecuteScript(const std::string& script,
894 NPVariant* result) {
895 NPObject* window = GetWindowObject();
896 if (!window) {
897 NOTREACHED();
898 return false;
899 }
900
901 NPString script_for_execution;
902 script_for_execution.UTF8Characters = script.c_str();
903 script_for_execution.UTF8Length = script.length();
904
905 return npapi::Evaluate(instance_, window, &script_for_execution, result);
906 }
907
908 NPObject* ChromeFrameNPAPI::JavascriptToNPObject(const std::string& script) {
909 // Convert the passed in script to an invocable NPObject
910 // To achieve this we save away the function in a dummy window property
911 // which is then read to get the script object representing the function.
912
913 std::string script_code =
914 "javascript:window.__cf_get_function_object =";
915
916 // If we are able to look up the name in the javascript namespace, then it
917 // means that the caller passed in a function name. Convert the function
918 // name to a NPObject we can invoke on.
919 if (IsValidJavascriptFunction(script)) {
920 script_code += script;
921 } else {
922 script_code += "new Function(\"";
923 script_code += script;
924 script_code += "\");";
925 }
926
927 NPVariant result;
928 if (!ExecuteScript(script_code, &result)) {
929 NOTREACHED();
930 return NULL;
931 }
932
933 DCHECK(result.type == NPVariantType_Object);
934 DCHECK(result.value.objectValue != NULL);
935 return result.value.objectValue;
936 }
937
938 bool ChromeFrameNPAPI::IsValidJavascriptFunction(const std::string& script) {
939 std::string script_code = "javascript:window['";
940 script_code += script;
941 script_code += "'];";
942
943 ScopedNpVariant result;
944 if (!ExecuteScript(script_code, &result)) {
945 NOTREACHED();
946 return NULL;
947 }
948
949 return result.type == NPVariantType_Object;
950 }
951
952 bool ChromeFrameNPAPI::NavigateToURL(const NPVariant* args, uint32_t arg_count,
953 NPVariant* result) {
954 // Note that 'result' might be NULL.
955 if (arg_count != 1 || !(NPVARIANT_IS_STRING(args[0]) ||
956 NPVARIANT_IS_NULL(args[0]))) {
957 NOTREACHED();
958 return false;
959 }
960
961 if (ready_state_ == READYSTATE_UNINITIALIZED) {
962 // Error(L"Chrome Frame failed to initialize.");
963 // TODO(tommi): call NPN_SetException
964 DLOG(WARNING) << "NavigateToURL called after failed initialization";
965 return false;
966 }
967
968 std::string url("about:blank");
969 if (!NPVARIANT_IS_NULL(args[0])) {
970 const NPString& str = args[0].value.stringValue;
971 if (str.UTF8Length) {
972 url.assign(std::string(str.UTF8Characters, str.UTF8Length));
973 }
974 }
975
976 GURL document_url(GetDocumentUrl());
977 if (document_url.SchemeIsSecure()) {
978 GURL source_url(url);
979 if (!source_url.SchemeIsSecure()) {
980 DLOG(WARNING) << __FUNCTION__ << " Prevnting navigation to HTTP url"
981 " since the containing document is HTTPS. URL: " << source_url <<
982 " Document URL: " << document_url;
983 return false;
984 }
985 }
986
987 std::string full_url = ResolveURL(GetDocumentUrl(), url);
988
989 src_ = full_url;
990 // Navigate only if we completed initialization i.e. proxy is set etc.
991 if (ready_state_ == READYSTATE_COMPLETE) {
992 if (!automation_client_->InitiateNavigation(full_url,
993 GetDocumentUrl(),
994 this)) {
995 // TODO(tommi): call NPN_SetException.
996 src_.clear();
997 return false;
998 }
999 } else {
1000 navigate_after_initialization_ = true;
1001 }
1002 return true;
1003 }
1004
1005 bool ChromeFrameNPAPI::postMessage(NPObject* npobject, const NPVariant* args,
1006 uint32_t arg_count, NPVariant* result) {
1007 // TODO(tommi) See if we can factor these checks out somehow.
1008 if (arg_count < 1 || arg_count > 2 || !NPVARIANT_IS_STRING(args[0])) {
1009 NOTREACHED();
1010 return false;
1011 }
1012
1013 const NPString& str = args[0].value.stringValue;
1014 std::string message(str.UTF8Characters, str.UTF8Length);
1015 std::string target;
1016 if (arg_count == 2 && NPVARIANT_IS_STRING(args[1])) {
1017 const NPString& str = args[1].value.stringValue;
1018 target.assign(str.UTF8Characters, str.UTF8Length);
1019 if (target.compare("*") != 0) {
1020 GURL resolved(target);
1021 if (!resolved.is_valid()) {
1022 npapi::SetException(npobject,
1023 "Unable to parse the specified target URL.");
1024 return false;
1025 }
1026 target = resolved.spec();
1027 }
1028 } else {
1029 target = "*";
1030 }
1031
1032 GURL url(GURL(document_url_).GetOrigin());
1033 std::string origin(url.is_empty() ? "null" : url.spec());
1034
1035 automation_client_->ForwardMessageFromExternalHost(message, origin, target);
1036
1037 return true;
1038 }
1039
1040 void ChromeFrameNPAPI::FireEvent(const std::string& event_type,
1041 const std::string& data) {
1042 NPVariant arg;
1043 STRINGN_TO_NPVARIANT(data.c_str(), data.length(), arg);
1044 FireEvent(event_type, arg);
1045 }
1046
1047 void ChromeFrameNPAPI::FireEvent(const std::string& event_type,
1048 const NPVariant& data) {
1049 // Check that we're not bundling an event inside an event.
1050 // Right now we're only expecting simple types for the data argument.
1051 DCHECK(NPVARIANT_IS_OBJECT(data) == false);
1052
1053 ScopedNpObject<NPObject> ev;
1054 CreateEvent(event_type, false, false, ev.Receive());
1055 if (ev) {
1056 // Add the 'data' member to the event.
1057 bool set = npapi::SetProperty(instance_, ev,
1058 npapi::GetStringIdentifier("data"), const_cast<NPVariant*>(&data));
1059 DCHECK(set);
1060 DispatchEvent(ev);
1061 }
1062 }
1063
1064 NPObject* ChromeFrameNPAPI::GetWindowObject() const {
1065 if (!window_object_.get() && instance_) {
1066 NPError ret = npapi::GetValue(instance_, NPNVWindowNPObject,
1067 window_object_.Receive());
1068 DLOG_IF(ERROR, ret != NPERR_NO_ERROR) << "NPNVWindowNPObject failed";
1069 }
1070 return window_object_;
1071 }
1072
1073 bool ChromeFrameNPAPI::GetBrowserIncognitoMode() {
1074 bool incognito_mode = false;
1075
1076 // Check disabled for Opera due to bug:
1077 // http://code.google.com/p/chromium/issues/detail?id=24287
1078 if (GetBrowserType() != BROWSER_OPERA) {
1079 // Check whether host browser is in private mode;
1080 NPBool private_mode = FALSE;
1081 NPError err = npapi::GetValue(instance_,
1082 NPNVprivateModeBool,
1083 &private_mode);
1084 if (err == NPERR_NO_ERROR && private_mode) {
1085 incognito_mode = true;
1086 }
1087 } else {
1088 DLOG(WARNING) << "Not checking for private mode in Opera";
1089 }
1090
1091 return incognito_mode;
1092 }
1093
1094 bool ChromeFrameNPAPI::PreProcessContextMenu(HMENU menu) {
1095 // TODO: Remove this overridden method once HandleContextMenuCommand
1096 // implements "About Chrome Frame" handling.
1097 if (!is_privileged()) {
1098 // Call base class (adds 'About' item).
1099 return ChromeFramePlugin::PreProcessContextMenu(menu);
1100 }
1101 return true;
1102 }
1103
1104 bool ChromeFrameNPAPI::HandleContextMenuCommand(
1105 UINT cmd, const MiniContextMenuParams& params) {
1106 if (cmd == IDC_ABOUT_CHROME_FRAME) {
1107 // TODO: implement "About Chrome Frame"
1108 }
1109 return false;
1110 }
1111
1112 NPError ChromeFrameNPAPI::NewStream(NPMIMEType type, NPStream* stream,
1113 NPBool seekable, uint16* stream_type) {
1114 return url_fetcher_.NewStream(type, stream, seekable, stream_type);
1115 }
1116
1117 int32 ChromeFrameNPAPI::WriteReady(NPStream* stream) {
1118 return url_fetcher_.WriteReady(stream);
1119 }
1120
1121 int32 ChromeFrameNPAPI::Write(NPStream* stream, int32 offset, int32 len,
1122 void* buffer) {
1123 return url_fetcher_.Write(stream, offset, len, buffer);
1124 }
1125
1126 NPError ChromeFrameNPAPI::DestroyStream(NPStream* stream, NPReason reason) {
1127 return url_fetcher_.DestroyStream(stream, reason);
1128 }
1129
1130 void ChromeFrameNPAPI::URLRedirectNotify(const char* url, int status,
1131 void* notify_data) {
1132 DVLOG(1) << __FUNCTION__
1133 << "Received redirect notification for url:"
1134 << url;
1135 // Inform chrome about the redirect and disallow the current redirect
1136 // attempt.
1137 url_fetcher_.UrlRedirectNotify(url, status, notify_data);
1138 npapi::URLRedirectResponse(instance_, notify_data, false);
1139 }
OLDNEW
« no previous file with comments | « chrome_frame/chrome_frame_npapi.h ('k') | chrome_frame/chrome_frame_npapi_entrypoints.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698