Chromium Code Reviews

Side by Side Diff: chrome_frame/chrome_frame_npapi.cc

Issue 218019: Initial import of the Chrome Frame codebase. Integration in chrome.gyp coming... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | | Annotate | Revision Log
« no previous file with comments | « chrome_frame/chrome_frame_npapi.h ('k') | chrome_frame/chrome_frame_npapi.rgs » ('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) 2009 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_util.h"
11 #include "base/win_util.h"
12 #include "chrome/test/automation/tab_proxy.h"
13 #include "chrome_frame/ff_privilege_check.h"
14 #include "chrome_frame/utils.h"
15
16 MessageLoop* ChromeFrameNPAPI::message_loop_ = NULL;
17 int ChromeFrameNPAPI::instance_count_ = 0;
18
19 static const char* kNpEventNames[] = {
20 "focus",
21 "blur",
22 };
23
24 NPClass ChromeFrameNPAPI::plugin_class_ = {
25 NP_CLASS_STRUCT_VERSION,
26 ChromeFrameNPAPI::AllocateObject,
27 ChromeFrameNPAPI::DeallocateObject,
28 ChromeFrameNPAPI::Invalidate,
29 ChromeFrameNPAPI::HasMethod,
30 ChromeFrameNPAPI::Invoke,
31 NULL, // invokeDefault
32 ChromeFrameNPAPI::HasProperty,
33 ChromeFrameNPAPI::GetProperty,
34 ChromeFrameNPAPI::SetProperty,
35 NULL, // remove property
36 NULL, // enumeration
37 NULL, // construct
38 };
39
40 NPIdentifier
41 ChromeFrameNPAPI::plugin_property_identifiers_[PLUGIN_PROPERTY_COUNT]
42 = {0};
43
44 const NPUTF8* ChromeFrameNPAPI::plugin_property_identifier_names_[] = {
45 "version",
46 "src",
47 "onload",
48 "onloaderror",
49 "onmessage",
50 "readystate",
51 "onprivatemessage",
52 "usechromenetwork",
53 };
54
55 const NPUTF8* ChromeFrameNPAPI::plugin_method_identifier_names_[] = {
56 "postMessage",
57 "postPrivateMessage",
58 };
59
60 ChromeFrameNPAPI::PluginMethod ChromeFrameNPAPI::plugin_methods_[] = {
61 &ChromeFrameNPAPI::postMessage,
62 &ChromeFrameNPAPI::postPrivateMessage,
63 };
64
65 NPIdentifier
66 ChromeFrameNPAPI::plugin_method_identifiers_[arraysize(plugin_methods_)]
67 = {0};
68
69
70 void ChromeFrameNPAPI::CompileAsserts() {
71 NOTREACHED(); // This function should never be invoked.
72
73 COMPILE_ASSERT(arraysize(plugin_method_identifier_names_) ==
74 arraysize(plugin_methods_),
75 you_must_add_both_plugin_method_and_name);
76
77 COMPILE_ASSERT(arraysize(plugin_property_identifier_names_) ==
78 arraysize(plugin_property_identifiers_),
79 you_must_add_both_plugin_property_and_name);
80 }
81
82 static const int kMaxBytesForPluginConsumption = 0x7FFFFFFF;
83
84 static const char kPluginSrcAttribute[] = "src";
85 static const char kPluginForceFullPageAttribute[] = "force_full_page";
86 static const char kPluginOnloadAttribute[] = "onload";
87 static const char kPluginOnErrorAttribute[] = "onloaderror";
88 static const char kPluginOnMessageAttribute[] = "onmessage";
89 static const char kPluginOnPrivateMessageAttribute[] = "onprivatemessage";
90 // These properties can only be set in arguments at control instantiation.
91 // When the privileged_mode property is provided and set to true, the control
92 // will probe for whether its hosting document has the system principal, in
93 // which case privileged mode will be enabled.
94 static const char kPluginPrivilegedModeAttribute[] = "privileged_mode";
95 // If privileged mode is enabled, the string value of this argument will
96 // be appended to the chrome.exe command line.
97 static const char kPluginChromeExtraArguments[] = "chrome_extra_arguments";
98 // If privileged mode is enabled, the string value of this argument will
99 // be used as the profile name for our chrome.exe instance.
100 static const char kPluginChromeProfileName[] = "chrome_profile_name";
101 // If chrome network stack is to be used
102 static const char kPluginUseChromeNetwork[] = "usechromenetwork";
103
104
105 NPError NPP_New(NPMIMEType plugin_type, NPP instance, uint16 mode, int16 argc,
106 char* argn[], char* argv[], NPSavedData* saved) {
107 if (instance == NULL)
108 return NPERR_INVALID_INSTANCE_ERROR;
109
110 ChromeFrameNPAPI::ChromeFrameNPObject* chrome_frame_npapi_obj =
111 reinterpret_cast<ChromeFrameNPAPI::ChromeFrameNPObject*>(
112 npapi::CreateObject(instance, ChromeFrameNPAPI::PluginClass()));
113 DCHECK(chrome_frame_npapi_obj != NULL);
114
115 ChromeFrameNPAPI* plugin_instance =
116 chrome_frame_npapi_obj->chrome_frame_plugin_instance;
117 DCHECK(plugin_instance != NULL);
118
119 // Note that we MUST set instance->pdata BEFORE calling Initialize. This is
120 // because Initialize can call back into the NPAPI host which will need the
121 // pdata field to be set.
122 chrome_frame_npapi_obj->chrome_frame_plugin_instance =
123 plugin_instance;
124 instance->pdata = chrome_frame_npapi_obj;
125
126 bool init = plugin_instance->Initialize(plugin_type, instance,
127 mode, argc, argn, argv);
128 DCHECK(init);
129
130 return NPERR_NO_ERROR;
131 }
132
133 NPError NPP_Destroy(NPP instance, NPSavedData** save) {
134 // Takes ownership and releases the object at the end of scope.
135 ScopedNpObject<ChromeFrameNPAPI::ChromeFrameNPObject> chrome_frame_npapi_obj(
136 reinterpret_cast<ChromeFrameNPAPI::ChromeFrameNPObject*>(
137 instance->pdata));
138
139 if (chrome_frame_npapi_obj.get()) {
140 ChromeFrameNPAPI* plugin_instance =
141 ChromeFrameNPAPI::ChromeFrameInstanceFromPluginInstance(instance);
142
143 plugin_instance->Uninitialize();
144 instance->pdata = NULL;
145 }
146
147 return NPERR_NO_ERROR;
148 }
149
150 NPError NPP_SetWindow(NPP instance, NPWindow* window_info) {
151 if (window_info == NULL) {
152 NOTREACHED();
153 return NPERR_GENERIC_ERROR;
154 }
155
156 ChromeFrameNPAPI* plugin_instance =
157 ChromeFrameNPAPI::ChromeFrameInstanceFromPluginInstance(instance);
158
159 if (plugin_instance == NULL) {
160 return NPERR_INVALID_INSTANCE_ERROR;
161 }
162
163 plugin_instance->SetWindow(window_info);
164 return NPERR_NO_ERROR;
165 }
166
167 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream,
168 NPBool seekable, uint16* stream_type) {
169 NPAPIUrlRequest* url_request = ChromeFrameNPAPI::ValidateRequest(
170 instance, stream->notifyData);
171 if (url_request) {
172 if (!url_request->OnStreamCreated(type, stream))
173 return NPERR_GENERIC_ERROR;
174 }
175
176 // We need to return the requested stream mode if we are returning a success
177 // code. If we don't do this it causes Opera to blow up.
178 *stream_type = NP_NORMAL;
179 return NPERR_NO_ERROR;
180 }
181
182 NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) {
183 NPAPIUrlRequest* url_request = ChromeFrameNPAPI::ValidateRequest(
184 instance, stream->notifyData);
185 if (url_request) {
186 url_request->OnStreamDestroyed(reason);
187 }
188
189 return NPERR_NO_ERROR;
190 }
191
192 NPError NPP_GetValue(NPP instance, NPPVariable variable, void* value) {
193 if (variable == NPPVpluginScriptableNPObject) {
194 void** plugin = reinterpret_cast<void**>(value);
195 ChromeFrameNPAPI::ChromeFrameNPObject* chrome_frame_npapi_obj =
196 reinterpret_cast<ChromeFrameNPAPI::ChromeFrameNPObject*>(
197 instance->pdata);
198 // Return value is expected to be retained
199 npapi::RetainObject(reinterpret_cast<NPObject*>(chrome_frame_npapi_obj));
200 *plugin = chrome_frame_npapi_obj;
201 return NPERR_NO_ERROR;
202 }
203 return NPERR_GENERIC_ERROR;
204 }
205
206 NPError NPP_SetValue(NPP instance, NPNVariable variable, void* value) {
207 return NPERR_GENERIC_ERROR;
208 }
209
210 int32 NPP_WriteReady(NPP instance, NPStream* stream) {
211 NPAPIUrlRequest* url_request = ChromeFrameNPAPI::ValidateRequest(
212 instance, stream->notifyData);
213 if (url_request) {
214 return url_request->OnWriteReady();
215 }
216
217 return kMaxBytesForPluginConsumption;
218 }
219
220 int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len,
221 void* buffer) {
222 NPAPIUrlRequest* url_request = ChromeFrameNPAPI::ValidateRequest(
223 instance, stream->notifyData);
224 if (url_request) {
225 return url_request->OnWrite(buffer, len);
226 }
227
228 return len;
229 }
230
231 void NPP_URLNotify(NPP instance, const char* url, NPReason reason,
232 void* notifyData) {
233 ChromeFrameNPAPI* plugin_instance =
234 ChromeFrameNPAPI::ChromeFrameInstanceFromPluginInstance(instance);
235 if (plugin_instance) {
236 plugin_instance->UrlNotify(url, reason, notifyData);
237 }
238 }
239
240 void NPP_Print(NPP instance, NPPrint* print_info) {
241 ChromeFrameNPAPI* plugin_instance =
242 ChromeFrameNPAPI::ChromeFrameInstanceFromPluginInstance(instance);
243
244 if (plugin_instance == NULL) {
245 NOTREACHED();
246 return;
247 }
248
249 plugin_instance->Print(print_info);
250 }
251
252 // ChromeFrameNPAPI member defines.
253
254 // TODO(tommi): remove ignore_setfocus_ since that's not how focus is
255 // handled anymore.
256
257 ChromeFrameNPAPI::ChromeFrameNPAPI()
258 : instance_(NULL),
259 mode_(NP_EMBED),
260 force_full_page_plugin_(false),
261 ready_state_(READYSTATE_LOADING),
262 enabled_popups_(false) {
263 }
264
265 ChromeFrameNPAPI::~ChromeFrameNPAPI() {
266 if (IsWindow()) {
267 if (!UnsubclassWindow()) {
268 // TODO(tommi): Figure out why this can sometimes happen in the
269 // WidgetModeFF_Resize unittest.
270 DLOG(ERROR) << "Couldn't unsubclass safely!";
271 UnsubclassWindow(TRUE);
272 }
273 }
274 m_hWnd = NULL;
275
276 instance_count_--;
277 if (instance_count_ <= 0) {
278 delete message_loop_;
279 message_loop_ = NULL;
280 }
281
282 Uninitialize();
283 }
284
285 std::string GetLocation(NPP instance, NPObject* window) {
286 if (!window) {
287 // Can fail if the browser is closing (seen in Opera).
288 return "";
289 }
290
291 std::string result;
292 ScopedNpVariant href;
293 ScopedNpVariant location;
294
295 bool ok = npapi::GetProperty(instance, window,
296 npapi::GetStringIdentifier("location"), &location);
297 DCHECK(ok);
298 DCHECK(location.type == NPVariantType_Object);
299
300 if (ok) {
301 ok = npapi::GetProperty(instance,
302 location.value.objectValue,
303 npapi::GetStringIdentifier("href"),
304 &href);
305 DCHECK(ok);
306 DCHECK(href.type == NPVariantType_String);
307 if (ok) {
308 result.assign(href.value.stringValue.UTF8Characters,
309 href.value.stringValue.UTF8Length);
310 }
311 }
312
313 return result;
314 }
315
316 std::string ChromeFrameNPAPI::GetLocation() {
317 // Note that GetWindowObject() will cache the window object here.
318 return ::GetLocation(instance_, GetWindowObject());
319 }
320
321 bool ChromeFrameNPAPI::Initialize(NPMIMEType mime_type, NPP instance,
322 uint16 mode, int16 argc, char* argn[],
323 char* argv[]) {
324 if (!Base::Initialize())
325 return false;
326
327 instance_ = instance;
328 mime_type_ = mime_type;
329 mode_ = mode;
330 document_url_ = GetLocation();
331
332 if (instance_count_ == 0) {
333 DCHECK(message_loop_ == NULL);
334 message_loop_ = new MessageLoop();
335 }
336
337 instance_count_++;
338
339 // Create our prefs service wrapper here.
340 DCHECK(!pref_service_.get());
341 pref_service_ = CreatePrefService();
342 if (!pref_service_.get()) {
343 NOTREACHED() << "new NpProxyService";
344 return false;
345 }
346
347 // Temporary variables for privileged only parameters
348 const char* onprivatemessage_arg = NULL;
349 const char* chrome_extra_arguments_arg = NULL;
350 const char* chrome_profile_name_arg = NULL;
351 bool chrome_network_arg_set = false;
352 bool chrome_network_arg = false;
353 bool wants_privileged = false;
354
355 for (int i = 0; i < argc; ++i) {
356 if (LowerCaseEqualsASCII(argn[i], kPluginSrcAttribute)) {
357 src_ = ResolveURL(GetDocumentUrl(), argv[i]);
358 } else if (LowerCaseEqualsASCII(argn[i], kPluginForceFullPageAttribute)) {
359 force_full_page_plugin_ = atoi(argv[i]) ? true : false;
360 } else if (LowerCaseEqualsASCII(argn[i], kPluginOnErrorAttribute)) {
361 onerror_handler_ = JavascriptToNPObject(argv[i]);
362 } else if (LowerCaseEqualsASCII(argn[i], kPluginOnMessageAttribute)) {
363 onmessage_handler_ = JavascriptToNPObject(argv[i]);
364 } else if (LowerCaseEqualsASCII(argn[i],
365 kPluginPrivilegedModeAttribute)) {
366 // Test for the FireFox privileged mode if the user requests it
367 // in initialization parameters.
368 wants_privileged = atoi(argv[i]) ? true : false;
369 } else if (LowerCaseEqualsASCII(argn[i],
370 kPluginOnPrivateMessageAttribute)) {
371 onprivatemessage_arg = argv[i];
372 } else if (LowerCaseEqualsASCII(argn[i], kPluginChromeExtraArguments)) {
373 chrome_extra_arguments_arg = argv[i];
374 } else if (LowerCaseEqualsASCII(argn[i], kPluginChromeProfileName)) {
375 chrome_profile_name_arg = argv[i];
376 } else if (LowerCaseEqualsASCII(argn[i], kPluginUseChromeNetwork)) {
377 chrome_network_arg_set = true;
378 chrome_network_arg = atoi(argv[i]) ? true : false;
379 }
380 }
381
382 // Is the privileged mode requested?
383 if (wants_privileged) {
384 is_privileged_ = IsFireFoxPrivilegedInvocation(instance);
385 if (!is_privileged_) {
386 DLOG(WARNING) << "Privileged mode requested in non-privileged context";
387 }
388 }
389
390 std::wstring extra_arguments;
391 std::wstring profile_name(GetHostProcessName(false));
392 if (is_privileged_) {
393 // Process any privileged mode-only arguments we were handed.
394 if (onprivatemessage_arg)
395 onprivatemessage_handler_ = JavascriptToNPObject(onprivatemessage_arg);
396
397 if (chrome_extra_arguments_arg)
398 extra_arguments = UTF8ToWide(chrome_extra_arguments_arg);
399
400 if (chrome_profile_name_arg)
401 profile_name = UTF8ToWide(chrome_profile_name_arg);
402
403 if (chrome_network_arg_set)
404 automation_client_->set_use_chrome_network(chrome_network_arg);
405
406 }
407
408 // TODO(joshia): Initialize navigation here and send proxy config as
409 // part of LaunchSettings
410 /*
411 if (!src_.empty())
412 automation_client_->InitiateNavigation(src_);
413
414 std::string proxy_settings;
415 bool has_prefs = pref_service_->Initialize(instance_,
416 automation_client_.get());
417 if (has_prefs && pref_service_->GetProxyValueJSONString(&proxy_settings)) {
418 automation_client_->SetProxySettings(proxy_settings);
419 }
420 */
421
422 // We can't call SubscribeToFocusEvents here since
423 // when Initialize gets called, Opera is in a state where
424 // it can't handle calls back and the thread will hang.
425 // Instead, we call SubscribeToFocusEvents when we initialize
426 // our plugin window.
427
428 // TODO(stoyan): Ask host for specific interface whether to honor
429 // host's in-private mode.
430 return InitializeAutomation(profile_name, extra_arguments,
431 GetBrowserIncognitoMode());
432 }
433
434 void ChromeFrameNPAPI::Uninitialize() {
435 // Don't call SetReadyState as it will end up calling FireEvent.
436 // We are in the context of NPP_DESTROY.
437 ready_state_ = READYSTATE_UNINITIALIZED;
438
439 UnsubscribeFromFocusEvents();
440
441 if (pref_service_) {
442 pref_service_->UnInitialize();
443 pref_service_ = NULL;
444 }
445
446 window_object_.Free();
447 onerror_handler_.Free();
448 onmessage_handler_.Free();
449 onprivatemessage_handler_.Free();
450
451 Base::Uninitialize();
452 }
453
454 void ChromeFrameNPAPI::OnFinalMessage(HWND window) {
455 // The automation server should be gone by now.
456 Uninitialize();
457 }
458
459 void ChromeFrameNPAPI::SubscribeToFocusEvents() {
460 DCHECK(focus_listener_.get() == NULL);
461
462 focus_listener_ = new DomEventListener(this);
463 if (!focus_listener_->Subscribe(instance_, kNpEventNames,
464 arraysize(kNpEventNames))) {
465 focus_listener_ = NULL;
466 focus_listener_ = new NPObjectEventListener(this);
467 if (!focus_listener_->Subscribe(instance_, kNpEventNames,
468 arraysize(kNpEventNames))) {
469 DLOG(ERROR) << "Failed to subscribe to focus events";
470 focus_listener_ = NULL;
471 }
472 }
473 }
474
475 void ChromeFrameNPAPI::UnsubscribeFromFocusEvents() {
476 if (!focus_listener_.get())
477 return;
478
479 bool ret = focus_listener_->Unsubscribe(instance_, kNpEventNames,
480 arraysize(kNpEventNames));
481 DLOG_IF(WARNING, !ret) << "focus_listener_->Unsubscribe failed";
482 focus_listener_ = NULL;
483 }
484
485 bool ChromeFrameNPAPI::SetWindow(NPWindow* window_info) {
486 if (!window_info || !automation_client_.get()) {
487 NOTREACHED();
488 return false;
489 }
490
491 HWND window = reinterpret_cast<HWND>(window_info->window);
492 if (!::IsWindow(window)) {
493 // No window created yet. Ignore this call.
494 return false;
495 }
496
497 if (IsWindow()) {
498 // We've already subclassed, make sure that SetWindow doesn't get called
499 // with an HWND other than the one we subclassed during our lifetime.
500 DCHECK(window == m_hWnd);
501 return true;
502 }
503
504 automation_client_->SetParentWindow(window);
505
506 SubscribeToFocusEvents();
507
508 if (force_full_page_plugin_) {
509 // By default full page mode is only enabled when the plugin is loaded off
510 // a separate file, i.e. it is the primary content in the window. Even if
511 // we specify the width/height attributes for the plugin as 100% each, FF
512 // instantiates the plugin passing in a width/height of 100px each. To
513 // workaround this we resize the plugin window passed in by FF to the size
514 // of its parent.
515 HWND plugin_parent_window = ::GetParent(window);
516 RECT plugin_parent_rect = {0};
517 ::GetClientRect(plugin_parent_window, &plugin_parent_rect);
518 ::SetWindowPos(window, NULL, plugin_parent_rect.left,
519 plugin_parent_rect.top,
520 plugin_parent_rect.right - plugin_parent_rect.left,
521 plugin_parent_rect.bottom - plugin_parent_rect.top, 0);
522 }
523
524 // Subclass the browser's plugin window here.
525 if (SubclassWindow(window)) {
526 DWORD new_style_flags = WS_CLIPCHILDREN;
527 ModifyStyle(0, new_style_flags, 0);
528
529 if (ready_state_ < READYSTATE_INTERACTIVE) {
530 SetReadyState(READYSTATE_INTERACTIVE);
531 }
532 }
533
534 return true;
535 }
536
537 void ChromeFrameNPAPI::Print(NPPrint* print_info) {
538 if (!print_info) {
539 NOTREACHED();
540 return;
541 }
542
543 // We dont support full tab mode yet.
544 if (print_info->mode != NP_EMBED) {
545 NOTREACHED();
546 return;
547 }
548
549 NPWindow window = print_info->print.embedPrint.window;
550
551 RECT print_bounds = {0};
552 print_bounds.left = window.x;
553 print_bounds.top = window.y;
554 print_bounds.right = window.x + window.width;
555 print_bounds.bottom = window.x + window.height;
556
557 automation_client_->Print(
558 reinterpret_cast<HDC>(print_info->print.embedPrint.platformPrint),
559 print_bounds);
560 }
561
562 void ChromeFrameNPAPI::UrlNotify(const char* url, NPReason reason,
563 void* notify_data) {
564 if (enabled_popups_) {
565 // We have opened the URL so tell the browser to restore popup settings
566 enabled_popups_ = false;
567 npapi::PopPopupsEnabledState(instance_);
568 }
569
570 // It is now safe to release the additional reference on the request
571 NPAPIUrlRequest* request = RequestFromNotifyData(notify_data);
572 if (request) {
573 request->Stop();
574 request->Release();
575 }
576 }
577
578 void ChromeFrameNPAPI::OnAcceleratorPressed(int tab_handle,
579 const MSG& accel_message) {
580 DLOG(INFO) << __FUNCTION__ << " msg:"
581 << StringPrintf("0x%04X", accel_message.message) << " key:"
582 << accel_message.wParam;
583
584 // The host browser does call TranslateMessage on messages like WM_KEYDOWN
585 // WM_KEYUP, etc, which will result in messages like WM_CHAR, WM_SYSCHAR, etc
586 // being posted to the message queue. We don't post these messages here to
587 // avoid these messages from getting handled twice.
588 if (accel_message.message != WM_CHAR &&
589 accel_message.message != WM_DEADCHAR &&
590 accel_message.message != WM_SYSCHAR &&
591 accel_message.message != WM_SYSDEADCHAR) {
592 // A very primitive way to handle keystrokes.
593 // TODO(tommi): When we've implemented a way for chrome to
594 // know when keystrokes are handled (deterministically) on that side,
595 // then this function should get called and not otherwise.
596 ::PostMessage(::GetParent(m_hWnd), accel_message.message,
597 accel_message.wParam, accel_message.lParam);
598 }
599
600 if (automation_client_.get()) {
601 TabProxy* tab = automation_client_->tab();
602 if (tab) {
603 tab->ProcessUnhandledAccelerator(accel_message);
604 }
605 }
606 }
607
608 void ChromeFrameNPAPI::OnTabbedOut(int tab_handle, bool reverse) {
609 DLOG(INFO) << __FUNCTION__;
610
611 ignore_setfocus_ = true;
612 HWND parent = ::GetParent(m_hWnd);
613 ::SetFocus(parent);
614
615 INPUT input = {0};
616 input.type = INPUT_KEYBOARD;
617 input.ki.wVk = VK_TAB;
618 SendInput(1, &input, sizeof(input));
619 input.ki.dwFlags = KEYEVENTF_KEYUP;
620 SendInput(1, &input, sizeof(input));
621
622 ignore_setfocus_ = false;
623 }
624
625 void ChromeFrameNPAPI::OnOpenURL(int tab_handle,
626 const GURL& url, int open_disposition) {
627 std::string target;
628 switch (open_disposition) {
629 case NEW_FOREGROUND_TAB:
630 target = "_blank";
631 break;
632 case NEW_BACKGROUND_TAB:
633 target = "_blank";
634 break;
635 case NEW_WINDOW:
636 target = "_new";
637 break;
638 default:
639 break;
640 }
641
642 // Tell the browser to temporarily allow popups
643 enabled_popups_ = true;
644 npapi::PushPopupsEnabledState(instance_, TRUE);
645 npapi::GetURLNotify(instance_, url.spec().c_str(), target.c_str(), NULL);
646 }
647
648 void ChromeFrameNPAPI::OnRequestStart(int tab_handle, int request_id,
649 const IPC::AutomationURLRequest& request) {
650 scoped_refptr<NPAPIUrlRequest> new_request(new NPAPIUrlRequest(instance_));
651 DCHECK(new_request);
652 if (new_request->Initialize(automation_client_.get(), tab_handle,
653 request_id, request.url, request.method,
654 request.referrer, request.extra_request_headers,
655 request.upload_data.get(), true)) {
656 if (new_request->Start()) {
657 // Keep additional reference on request for NPSTREAM
658 // This will be released in NPP_UrlNotify
659 new_request->AddRef();
660 }
661 }
662 }
663
664 void ChromeFrameNPAPI::OnRequestRead(int tab_handle, int request_id,
665 int bytes_to_read) {
666 automation_client_->ReadRequest(request_id, bytes_to_read);
667 }
668
669 void ChromeFrameNPAPI::OnRequestEnd(int tab_handle, int request_id,
670 const URLRequestStatus& status) {
671 automation_client_->RemoveRequest(request_id, status.status(), true);
672 }
673
674 void ChromeFrameNPAPI::OnSetCookieAsync(int tab_handle, const GURL& url,
675 const std::string& cookie) {
676 // Use the newer NPAPI way if available
677 if (npapi::VersionMinor() >= NPVERS_HAS_URL_AND_AUTH_INFO) {
678 npapi::SetValueForURL(instance_, NPNURLVCookie, url.spec().c_str(),
679 cookie.c_str(), cookie.length());
680 } else if (url == GURL(document_url_)) {
681 std::string script = "javascript:document.cookie=";
682 script.append(cookie);
683 script.append(1, ';');
684 ExecuteScript(script, NULL);
685 } else {
686 // Third party cookie, use nsICookieService to set the cookie.
687 NOTREACHED();
688 }
689 }
690
691 bool ChromeFrameNPAPI::HasMethod(NPObject* obj, NPIdentifier name) {
692 for (int i = 0; i < arraysize(plugin_methods_); ++i) {
693 if (name == plugin_method_identifiers_[i])
694 return true;
695 }
696
697 return false;
698 }
699
700 bool ChromeFrameNPAPI::Invoke(NPObject* header, NPIdentifier name,
701 const NPVariant* args, uint32_t arg_count,
702 NPVariant* result) {
703 ChromeFrameNPAPI* plugin_instance = ChromeFrameInstanceFromNPObject(header);
704 if (!plugin_instance && (plugin_instance->automation_client_.get()))
705 return false;
706
707 bool success = false;
708 for (int i = 0; i < arraysize(plugin_methods_); ++i) {
709 if (name == plugin_method_identifiers_[i]) {
710 PluginMethod method = plugin_methods_[i];
711 success = (plugin_instance->*method)(header, args, arg_count, result);
712 break;
713 }
714 }
715
716 return success;
717 }
718
719 void ChromeFrameNPAPI::InitializeIdentifiers() {
720 npapi::GetStringIdentifiers(plugin_method_identifier_names_,
721 arraysize(plugin_methods_),
722 plugin_method_identifiers_);
723
724 npapi::GetStringIdentifiers(plugin_property_identifier_names_,
725 PLUGIN_PROPERTY_COUNT,
726 plugin_property_identifiers_);
727 }
728
729 NPObject* ChromeFrameNPAPI::AllocateObject(NPP instance, NPClass* class_name) {
730 static bool identifiers_initialized = false;
731
732 ChromeFrameNPObject* plugin_object = new ChromeFrameNPObject();
733 DCHECK(plugin_object != NULL);
734
735 plugin_object->chrome_frame_plugin_instance = new ChromeFrameNPAPI();
736 DCHECK(plugin_object->chrome_frame_plugin_instance != NULL);
737
738 plugin_object->npp = NULL;
739
740 COMPILE_ASSERT(arraysize(plugin_method_identifiers_) ==
741 arraysize(plugin_method_identifier_names_),
742 method_count_mismatch);
743
744 COMPILE_ASSERT(arraysize(plugin_method_identifiers_) ==
745 arraysize(plugin_methods_),
746 method_count_mismatch);
747
748 if (!identifiers_initialized) {
749 InitializeIdentifiers();
750 identifiers_initialized = true;
751 }
752
753 return reinterpret_cast<NPObject*>(plugin_object);
754 }
755
756 void ChromeFrameNPAPI::DeallocateObject(NPObject* header) {
757 ChromeFrameNPObject* plugin_object =
758 reinterpret_cast<ChromeFrameNPObject*>(header);
759 DCHECK(plugin_object != NULL);
760
761 if (plugin_object) {
762 delete plugin_object->chrome_frame_plugin_instance;
763 delete plugin_object;
764 }
765 }
766
767 void ChromeFrameNPAPI::Invalidate(NPObject* header) {
768 DCHECK(header);
769 ChromeFrameNPObject* plugin_object =
770 reinterpret_cast<ChromeFrameNPObject*>(header);
771 if (plugin_object) {
772 DCHECK(plugin_object->chrome_frame_plugin_instance);
773 plugin_object->chrome_frame_plugin_instance->Uninitialize();
774 }
775 }
776
777 ChromeFrameNPAPI* ChromeFrameNPAPI::ChromeFrameInstanceFromPluginInstance(
778 NPP instance) {
779 if ((instance == NULL) || (instance->pdata == NULL)) {
780 NOTREACHED();
781 return NULL;
782 }
783
784 return ChromeFrameInstanceFromNPObject(instance->pdata);
785 }
786
787 ChromeFrameNPAPI* ChromeFrameNPAPI::ChromeFrameInstanceFromNPObject(
788 void* object) {
789 ChromeFrameNPObject* plugin_object =
790 reinterpret_cast<ChromeFrameNPObject*>(object);
791 if (!plugin_object) {
792 NOTREACHED();
793 return NULL;
794 }
795
796 DCHECK(plugin_object->chrome_frame_plugin_instance);
797 return plugin_object->chrome_frame_plugin_instance;
798 }
799
800 bool ChromeFrameNPAPI::HasProperty(NPObject* obj, NPIdentifier name) {
801 for (int i = 0; i < PLUGIN_PROPERTY_COUNT; ++i) {
802 if (name == plugin_property_identifiers_[i])
803 return true;
804 }
805 return false;
806 }
807
808 bool ChromeFrameNPAPI::GetProperty(NPIdentifier name,
809 NPVariant* variant) {
810 if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_ONERROR]) {
811 if (onerror_handler_) {
812 variant->type = NPVariantType_Object;
813 variant->value.objectValue = onerror_handler_.Copy();
814 return true;
815 }
816 } else if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_ONMESSAGE]) {
817 if (onmessage_handler_) {
818 variant->type = NPVariantType_Object;
819 variant->value.objectValue = onmessage_handler_.Copy();
820 return true;
821 }
822 } else if (name ==
823 plugin_property_identifiers_[PLUGIN_PROPERTY_ONPRIVATEMESSAGE]) {
824 if (!is_privileged_) {
825 DLOG(WARNING) << "Attempt to read onprivatemessage property while not "
826 "privileged";
827 } else {
828 if (onprivatemessage_handler_) {
829 variant->type = NPVariantType_Object;
830 variant->value.objectValue =
831 onprivatemessage_handler_.Copy();
832 return true;
833 }
834 }
835 } else if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_SRC]) {
836 AllocateStringVariant(src_, variant);
837 return true;
838 } else if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_VERSION]) {
839 const std::wstring version =
840 automation_client_->GetVersion();
841 AllocateStringVariant(WideToUTF8(version), variant);
842 return true;
843 } else if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_READYSTATE]) {
844 INT32_TO_NPVARIANT(ready_state_, *variant);
845 return true;
846 } else if (name ==
847 plugin_property_identifiers_[PLUGIN_PROPERTY_USECHROMENETWORK]) {
848 BOOLEAN_TO_NPVARIANT(automation_client_->use_chrome_network(), *variant);
849 return true;
850 }
851
852 return false;
853 }
854
855 bool ChromeFrameNPAPI::GetProperty(NPObject* object, NPIdentifier name,
856 NPVariant* variant) {
857 if (!object || !variant) {
858 NOTREACHED();
859 return false;
860 }
861
862 ChromeFrameNPAPI* plugin_instance = ChromeFrameInstanceFromNPObject(object);
863 if (!plugin_instance) {
864 NOTREACHED();
865 return false;
866 }
867
868 return plugin_instance->GetProperty(name, variant);
869 }
870
871 bool ChromeFrameNPAPI::SetProperty(NPIdentifier name,
872 const NPVariant* variant) {
873 if (NPVARIANT_IS_OBJECT(*variant)) {
874 if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_ONERROR]) {
875 onerror_handler_.Free();
876 onerror_handler_ = variant->value.objectValue;
877 return true;
878 } else if (
879 name == plugin_property_identifiers_[PLUGIN_PROPERTY_ONMESSAGE]) {
880 onmessage_handler_.Free();
881 onmessage_handler_ = variant->value.objectValue;
882 return true;
883 } else if (name ==
884 plugin_property_identifiers_[PLUGIN_PROPERTY_ONPRIVATEMESSAGE]) {
885 if (!is_privileged_) {
886 DLOG(WARNING) << "Attempt to set onprivatemessage while not privileged";
887 } else {
888 onprivatemessage_handler_.Free();
889 onprivatemessage_handler_ = variant->value.objectValue;
890 return true;
891 }
892 }
893 } else if (NPVARIANT_IS_STRING(*variant) || NPVARIANT_IS_NULL(*variant)) {
894 if (name == plugin_property_identifiers_[PLUGIN_PROPERTY_SRC]) {
895 return NavigateToURL(variant, 1, NULL);
896 }
897 } else if (NPVARIANT_IS_BOOLEAN(*variant)) {
898 if (name ==
899 plugin_property_identifiers_[PLUGIN_PROPERTY_USECHROMENETWORK]) {
900 automation_client_->set_use_chrome_network(
901 NPVARIANT_TO_BOOLEAN(*variant));
902 }
903 }
904
905 return false;
906 }
907
908 bool ChromeFrameNPAPI::SetProperty(NPObject* object, NPIdentifier name,
909 const NPVariant* variant) {
910 if (!object || !variant) {
911 DLOG(ERROR) << "Cannot set property: " << npapi::StringFromIdentifier(name);
912 return false;
913 }
914
915 ChromeFrameNPAPI* plugin_instance = ChromeFrameInstanceFromNPObject(object);
916 if (!plugin_instance) {
917 NOTREACHED();
918 return false;
919 }
920
921 return plugin_instance->SetProperty(name, variant);
922 }
923
924 void ChromeFrameNPAPI::OnFocus() {
925 DLOG(INFO) << __FUNCTION__;
926 PostMessage(WM_SETFOCUS, 0, 0);
927 }
928
929 void ChromeFrameNPAPI::OnEvent(const char* event_name) {
930 DCHECK(event_name);
931 DLOG(INFO) << event_name;
932
933 if (lstrcmpiA(event_name, "focus") == 0) {
934 OnFocus();
935 } else if (lstrcmpiA(event_name, "blur") == 0) {
936 OnBlur();
937 } else {
938 NOTREACHED() << event_name;
939 }
940 }
941
942 LRESULT CALLBACK ChromeFrameNPAPI::DropKillFocusHook(int code, WPARAM wparam,
943 LPARAM lparam) {
944 LRESULT ret = 0;
945 CWPSTRUCT* wp = reinterpret_cast<CWPSTRUCT*>(lparam);
946 if ((code < 0) || (wp->message != WM_KILLFOCUS))
947 ret = ::CallNextHookEx(NULL, code, wparam, lparam);
948
949 return ret;
950 }
951
952 LRESULT ChromeFrameNPAPI::OnSetFocus(UINT message, WPARAM wparam,
953 LPARAM lparam, BOOL& handled) { // NO_LINT
954 // Opera has a WH_CALLWNDPROC hook that handles WM_KILLFOCUS and
955 // prevents us from setting the focus to the tab.
956 // To work around that, we set a temporary hook here that does nothing
957 // (not even call other hooks) when it sees WM_KILLFOCUS.
958 HHOOK hook = NULL;
959 hook = ::SetWindowsHookEx(WH_CALLWNDPROC, DropKillFocusHook, NULL,
960 ::GetCurrentThreadId());
961 // Since we chain message maps, make sure we are not calling base class
962 // twice for WM_SETFOCUS.
963 BOOL handled_by_base = TRUE;
964 LRESULT ret = Base::OnSetFocus(message, wparam, lparam, handled_by_base);
965 if (hook)
966 ::UnhookWindowsHookEx(hook);
967
968 return ret;
969 }
970
971 void ChromeFrameNPAPI::OnBlur() {
972 DLOG(INFO) << __FUNCTION__;
973 }
974
975 void ChromeFrameNPAPI::OnLoad(int, const GURL& gurl) {
976 DLOG(INFO) << "Firing onload";
977 FireEvent("load", gurl.spec());
978 }
979
980 void ChromeFrameNPAPI::OnLoadFailed(int error_code, const std::string& url) {
981 FireEvent("loaderror", url);
982
983 ScopedNpVariant result;
984 InvokeDefault(onerror_handler_, url, &result);
985 }
986
987 void ChromeFrameNPAPI::OnMessageFromChromeFrame(int tab_handle,
988 const std::string& message,
989 const std::string& origin,
990 const std::string& target) {
991 bool private_message = false;
992 if (target.compare("*") != 0) {
993 if (is_privileged_) {
994 private_message = true;
995 } else {
996 if (!HaveSameOrigin(target, document_url_)) {
997 DLOG(WARNING) << "Dropping posted message since target doesn't match "
998 "the current document's origin. target=" << target;
999 return;
1000 }
1001 }
1002 }
1003
1004 // Create a MessageEvent object that contains the message and origin
1005 // as well as supporting other MessageEvent (see the HTML5 spec) properties.
1006 // Then call the onmessage handler.
1007 ScopedNpObject<NPObject> event;
1008 bool ok = CreateMessageEvent(false, true, message, origin, event.Receive());
1009 if (ok) {
1010 // Don't call FireEvent here (or we'll have an event wrapped by an event).
1011 DispatchEvent(event);
1012
1013 ScopedNpVariant result;
1014 NPVariant params[2];
1015 OBJECT_TO_NPVARIANT(event, params[0]);
1016 bool invoke = false;
1017 if (private_message) {
1018 DCHECK(is_privileged_);
1019 STRINGN_TO_NPVARIANT(target.c_str(), target.length(), params[1]);
1020 invoke = InvokeDefault(onprivatemessage_handler_,
1021 arraysize(params),
1022 params,
1023 &result);
1024 } else {
1025 invoke = InvokeDefault(onmessage_handler_, params[0], &result);
1026 }
1027 DLOG_IF(WARNING, !invoke) << "InvokeDefault failed";
1028 } else {
1029 NOTREACHED() << "CreateMessageEvent";
1030 }
1031 }
1032
1033 void ChromeFrameNPAPI::OnAutomationServerReady() {
1034 Base::OnAutomationServerReady();
1035
1036 std::string proxy_settings;
1037 bool has_prefs = pref_service_->Initialize(instance_,
1038 automation_client_.get());
1039 if (has_prefs && pref_service_->GetProxyValueJSONString(&proxy_settings)) {
1040 automation_client_->SetProxySettings(proxy_settings);
1041 }
1042
1043 if (!src_.empty()) {
1044 if (!automation_client_->InitiateNavigation(src_)) {
1045 DLOG(ERROR) << "Failed to navigate to: " << src_;
1046 src_.clear();
1047 }
1048 }
1049
1050 SetReadyState(READYSTATE_COMPLETE);
1051 }
1052
1053 void ChromeFrameNPAPI::OnAutomationServerLaunchFailed(
1054 AutomationLaunchResult reason, const std::string& server_version) {
1055 SetReadyState(READYSTATE_UNINITIALIZED);
1056
1057 if (reason == AUTOMATION_VERSION_MISMATCH) {
1058 DisplayVersionMismatchWarning(m_hWnd, server_version);
1059 }
1060 }
1061
1062 bool ChromeFrameNPAPI::InvokeDefault(NPObject* object,
1063 unsigned param_count,
1064 const NPVariant* params,
1065 NPVariant* result) {
1066 if (!object)
1067 return false;
1068
1069 bool ret = npapi::InvokeDefault(instance_, object, params, param_count,
1070 result);
1071 // InvokeDefault can return false in FF even though we do see the call
1072 // go through. It's not clear to me what the circumstances are, so
1073 // we log it as a warning while tracking it down.
1074 DLOG_IF(WARNING, !ret) << "npapi::InvokeDefault failed";
1075 return ret;
1076 }
1077
1078 bool ChromeFrameNPAPI::InvokeDefault(NPObject* object, const std::string& param,
1079 NPVariant* result) {
1080 NPVariant arg;
1081 STRINGN_TO_NPVARIANT(param.c_str(), param.length(), arg);
1082 return InvokeDefault(object, arg, result);
1083 }
1084
1085 bool ChromeFrameNPAPI::InvokeDefault(NPObject* object, const NPVariant& param,
1086 NPVariant* result) {
1087 return InvokeDefault(object, 1, &param, result);
1088 }
1089
1090 bool ChromeFrameNPAPI::CreateEvent(const std::string& type, bool bubbles,
1091 bool cancelable, NPObject** basic_event) {
1092 DCHECK(basic_event);
1093 NPObject* window = GetWindowObject();
1094 if (!window) {
1095 // Can fail if the browser is closing (seen in Opera).
1096 return false;
1097 }
1098
1099 const char* identifier_names[] = {
1100 "document",
1101 "createEvent",
1102 "initEvent",
1103 };
1104
1105 NPIdentifier identifiers[arraysize(identifier_names)];
1106 npapi::GetStringIdentifiers(identifier_names, arraysize(identifier_names),
1107 identifiers);
1108
1109 // Fetch the document object from the window.
1110 ScopedNpVariant document;
1111 bool ok = npapi::GetProperty(instance_, window, identifiers[0], &document);
1112 if (!ok) {
1113 // This could happen if the page is being unloaded.
1114 DLOG(WARNING) << "Failed to fetch the document object";
1115 return false;
1116 }
1117
1118 bool success = false;
1119 if (ok && NPVARIANT_IS_OBJECT(document)) {
1120 // Call document.createEvent("Event") to create a basic event object.
1121 NPVariant event_type;
1122 STRINGN_TO_NPVARIANT("Event", sizeof("Event") - 1, event_type);
1123 ScopedNpVariant result;
1124 success = npapi::Invoke(instance_, NPVARIANT_TO_OBJECT(document),
1125 identifiers[1], &event_type, 1, &result);
1126 if (!NPVARIANT_IS_OBJECT(result)) {
1127 DLOG(WARNING) << "Failed to invoke createEvent";
1128 success = false;
1129 } else {
1130 NPVariant init_args[3];
1131 STRINGN_TO_NPVARIANT(type.c_str(), type.length(), init_args[0]);
1132 BOOLEAN_TO_NPVARIANT(bubbles, init_args[1]);
1133 BOOLEAN_TO_NPVARIANT(cancelable, init_args[2]);
1134
1135 // Now initialize the event object by calling
1136 // event.initEvent(type, bubbles, cancelable);
1137 ScopedNpVariant init_results;
1138 ok = npapi::Invoke(instance_, NPVARIANT_TO_OBJECT(result), identifiers[2],
1139 init_args, arraysize(init_args), &init_results);
1140 if (ok) {
1141 success = true;
1142 // Finally, pass the ownership to the caller.
1143 *basic_event = NPVARIANT_TO_OBJECT(result);
1144 VOID_TO_NPVARIANT(result); // Prevent the object from being released.
1145 } else {
1146 DLOG(ERROR) << "initEvent failed";
1147 success = false;
1148 }
1149 }
1150 }
1151
1152 return success;
1153 }
1154
1155 bool ChromeFrameNPAPI::CreateMessageEvent(bool bubbles, bool cancelable,
1156 const std::string& data,
1157 const std::string& origin,
1158 NPObject** message_event) {
1159 DCHECK(message_event);
1160 ScopedNpObject<NPObject> event;
1161 bool ok = CreateEvent("message", false, true, event.Receive());
1162 if (ok) {
1163 typedef enum {
1164 DATA,
1165 ORIGIN,
1166 LAST_EVENT_ID,
1167 SOURCE,
1168 MESSAGE_PORT,
1169 IDENTIFIER_COUNT, // Must be last.
1170 } StringIdentifiers;
1171
1172 static NPIdentifier identifiers[IDENTIFIER_COUNT] = {0};
1173 if (!identifiers[0]) {
1174 const NPUTF8* identifier_names[] = {
1175 "data",
1176 "origin",
1177 "lastEventId",
1178 "source",
1179 "messagePort",
1180 };
1181 COMPILE_ASSERT(arraysize(identifier_names) == arraysize(identifiers),
1182 mismatched_array_size);
1183 npapi::GetStringIdentifiers(identifier_names, IDENTIFIER_COUNT,
1184 identifiers);
1185 }
1186
1187 NPVariant arg;
1188 STRINGN_TO_NPVARIANT(data.c_str(), data.length(), arg);
1189 npapi::SetProperty(instance_, event, identifiers[DATA], &arg);
1190 STRINGN_TO_NPVARIANT(origin.c_str(), origin.length(), arg);
1191 npapi::SetProperty(instance_, event, identifiers[ORIGIN], &arg);
1192 STRINGN_TO_NPVARIANT("", 0, arg);
1193 npapi::SetProperty(instance_, event, identifiers[LAST_EVENT_ID], &arg);
1194 NULL_TO_NPVARIANT(arg);
1195 npapi::SetProperty(instance_, event, identifiers[SOURCE], &arg);
1196 npapi::SetProperty(instance_, event, identifiers[MESSAGE_PORT], &arg);
1197 *message_event = event.Detach();
1198 }
1199
1200 return ok;
1201 }
1202
1203
1204 void ChromeFrameNPAPI::DispatchEvent(NPObject* event) {
1205 DCHECK(event != NULL);
1206
1207 ScopedNpObject<NPObject> embed;
1208 npapi::GetValue(instance_, NPNVPluginElementNPObject, &embed);
1209 if (embed != NULL) {
1210 NPVariant param;
1211 OBJECT_TO_NPVARIANT(event, param);
1212 ScopedNpVariant result;
1213 bool invoke = npapi::Invoke(instance_, embed,
1214 npapi::GetStringIdentifier("dispatchEvent"), &param, 1, &result);
1215 DLOG_IF(WARNING, !invoke) << "dispatchEvent failed";
1216 } else {
1217 NOTREACHED() << "NPNVPluginElementNPObject";
1218 }
1219 }
1220
1221 bool ChromeFrameNPAPI::ExecuteScript(const std::string& script,
1222 NPVariant* result) {
1223 NPObject* window = GetWindowObject();
1224 if (!window) {
1225 NOTREACHED();
1226 return false;
1227 }
1228
1229 NPString script_for_execution;
1230 script_for_execution.UTF8Characters = script.c_str();
1231 script_for_execution.UTF8Length = script.length();
1232
1233 return npapi::Evaluate(instance_, window, &script_for_execution, result);
1234 }
1235
1236 NPObject* ChromeFrameNPAPI::JavascriptToNPObject(const std::string& script) {
1237 // Convert the passed in script to an invocable NPObject
1238 // To achieve this we save away the function in a dummy window property
1239 // which is then read to get the script object representing the function.
1240
1241 std::string script_code =
1242 "javascript:window.__cf_get_function_object =";
1243
1244 // If we are able to look up the name in the javascript namespace, then it
1245 // means that the caller passed in a function name. Convert the function
1246 // name to a NPObject we can invoke on.
1247 if (IsValidJavascriptFunction(script)) {
1248 script_code += script;
1249 } else {
1250 script_code += "new Function(\"";
1251 script_code += script;
1252 script_code += "\");";
1253 }
1254
1255 NPVariant result;
1256 if (!ExecuteScript(script_code, &result)) {
1257 NOTREACHED();
1258 return NULL;
1259 }
1260
1261 DCHECK(result.type == NPVariantType_Object);
1262 DCHECK(result.value.objectValue != NULL);
1263 return result.value.objectValue;
1264 }
1265
1266 bool ChromeFrameNPAPI::IsValidJavascriptFunction(const std::string& script) {
1267 std::string script_code = "javascript:window['";
1268 script_code += script;
1269 script_code += "'];";
1270
1271 ScopedNpVariant result;
1272 if (!ExecuteScript(script_code, &result)) {
1273 NOTREACHED();
1274 return NULL;
1275 }
1276
1277 return result.type == NPVariantType_Object;
1278 }
1279
1280 bool ChromeFrameNPAPI::NavigateToURL(const NPVariant* args, uint32_t arg_count,
1281 NPVariant* result) {
1282 // Note that 'result' might be NULL.
1283 if (arg_count != 1 || !(NPVARIANT_IS_STRING(args[0]) ||
1284 NPVARIANT_IS_NULL(args[0]))) {
1285 NOTREACHED();
1286 return false;
1287 }
1288
1289 if (ready_state_ == READYSTATE_UNINITIALIZED) {
1290 // Error(L"Chrome Frame failed to initialize.");
1291 // TODO(tommi): call NPN_SetException
1292 DLOG(WARNING) << "NavigateToURL called after failed initialization";
1293 return false;
1294 }
1295
1296 std::string url("about:blank");
1297
1298 if (!NPVARIANT_IS_NULL(args[0])) {
1299 const NPString& str = args[0].value.stringValue;
1300 if (str.UTF8Length) {
1301 url.assign(std::string(str.UTF8Characters, str.UTF8Length));
1302 }
1303 }
1304 DLOG(WARNING) << __FUNCTION__ << " " << url;
1305 std::string full_url = ResolveURL(GetDocumentUrl(), url);
1306 if (full_url.empty())
1307 return false;
1308
1309 src_ = full_url;
1310 // Navigate only if we completed initialization i.e. proxy is set etc.
1311 if (ready_state_ == READYSTATE_COMPLETE) {
1312 if (!automation_client_->InitiateNavigation(full_url)) {
1313 // TODO(tommi): call NPN_SetException.
1314 src_.clear();
1315 return false;
1316 }
1317 }
1318 return true;
1319 }
1320
1321 bool ChromeFrameNPAPI::postMessage(NPObject* npobject, const NPVariant* args,
1322 uint32_t arg_count, NPVariant* result) {
1323 if (arg_count < 1 || arg_count > 2 || !NPVARIANT_IS_STRING(args[0])) {
1324 NOTREACHED();
1325 return false;
1326 }
1327
1328 const NPString& str = args[0].value.stringValue;
1329 std::string message(str.UTF8Characters, str.UTF8Length);
1330 std::string target;
1331 if (arg_count == 2 && NPVARIANT_IS_STRING(args[1])) {
1332 const NPString& str = args[1].value.stringValue;
1333 target.assign(str.UTF8Characters, str.UTF8Length);
1334 if (target.compare("*") != 0) {
1335 GURL resolved(target);
1336 if (!resolved.is_valid()) {
1337 npapi::SetException(npobject,
1338 "Unable to parse the specified target URL.");
1339 return false;
1340 }
1341 target = resolved.spec();
1342 }
1343 } else {
1344 target = "*";
1345 }
1346
1347 GURL url(GURL(document_url_).GetOrigin());
1348 std::string origin(url.is_empty() ? "null" : url.spec());
1349
1350 automation_client_->ForwardMessageFromExternalHost(message, origin, target);
1351
1352 return true;
1353 }
1354
1355 bool ChromeFrameNPAPI::postPrivateMessage(NPObject* npobject,
1356 const NPVariant* args,
1357 uint32_t arg_count,
1358 NPVariant* result) {
1359 if (!is_privileged_) {
1360 DLOG(WARNING) << "postPrivateMessage invoked in non-privileged mode";
1361 return false;
1362 }
1363
1364 if (arg_count != 3 || !NPVARIANT_IS_STRING(args[0]) ||
1365 !NPVARIANT_IS_STRING(args[1]) || !NPVARIANT_IS_STRING(args[2])) {
1366 NOTREACHED();
1367 return false;
1368 }
1369
1370 const NPString& message_str = args[0].value.stringValue;
1371 const NPString& origin_str = args[1].value.stringValue;
1372 const NPString& target_str = args[2].value.stringValue;
1373 std::string message(message_str.UTF8Characters, message_str.UTF8Length);
1374 std::string origin(origin_str.UTF8Characters, origin_str.UTF8Length);
1375 std::string target(target_str.UTF8Characters, target_str.UTF8Length);
1376
1377 automation_client_->ForwardMessageFromExternalHost(message, origin, target);
1378
1379 return true;
1380 }
1381
1382 void ChromeFrameNPAPI::FireEvent(const std::string& event_type,
1383 const std::string& data) {
1384 NPVariant arg;
1385 STRINGN_TO_NPVARIANT(data.c_str(), data.length(), arg);
1386 FireEvent(event_type, arg);
1387 }
1388
1389 void ChromeFrameNPAPI::FireEvent(const std::string& event_type,
1390 const NPVariant& data) {
1391 // Check that we're not bundling an event inside an event.
1392 // Right now we're only expecting simple types for the data argument.
1393 DCHECK(NPVARIANT_IS_OBJECT(data) == false);
1394
1395 ScopedNpObject<NPObject> ev;
1396 CreateEvent(event_type, false, false, ev.Receive());
1397 if (ev) {
1398 // Add the 'data' member to the event.
1399 bool set = npapi::SetProperty(instance_, ev,
1400 npapi::GetStringIdentifier("data"), const_cast<NPVariant*>(&data));
1401 DCHECK(set);
1402 DispatchEvent(ev);
1403 }
1404 }
1405
1406 NpProxyService* ChromeFrameNPAPI::CreatePrefService() {
1407 return new NpProxyService;
1408 }
1409
1410 NPObject* ChromeFrameNPAPI::GetWindowObject() const {
1411 if (!window_object_.get()) {
1412 NPError ret = npapi::GetValue(instance_, NPNVWindowNPObject,
1413 window_object_.Receive());
1414 DLOG_IF(ERROR, ret != NPERR_NO_ERROR) << "NPNVWindowNPObject failed";
1415 }
1416 return window_object_;
1417 }
1418
1419 bool ChromeFrameNPAPI::GetBrowserIncognitoMode() {
1420 bool incognito_mode = false;
1421
1422 // Check disabled for Opera due to bug: http://b/issue?id=1815494
1423 if (GetBrowserType() != BROWSER_OPERA) {
1424 // Check whether host browser is in private mode;
1425 NPBool private_mode = FALSE;
1426 NPError err = npapi::GetValue(instance_,
1427 NPNVprivateModeBool,
1428 &private_mode);
1429 if (err == NPERR_NO_ERROR && private_mode) {
1430 incognito_mode = true;
1431 }
1432 } else {
1433 DLOG(WARNING) << "Not checking for private mode in Opera";
1434 }
1435
1436 return incognito_mode;
1437 }
1438
1439 NPAPIUrlRequest* ChromeFrameNPAPI::ValidateRequest(
1440 NPP instance, void* notify_data) {
1441 ChromeFrameNPAPI* plugin_instance =
1442 ChromeFrameNPAPI::ChromeFrameInstanceFromPluginInstance(instance);
1443 if (plugin_instance) {
1444 return plugin_instance->RequestFromNotifyData(notify_data);
1445 }
1446
1447 return NULL;
1448 }
1449
1450 NPAPIUrlRequest* ChromeFrameNPAPI::RequestFromNotifyData(
1451 void* notify_data) const {
1452 NPAPIUrlRequest* request = reinterpret_cast<NPAPIUrlRequest*>(notify_data);
1453 DCHECK(request ? automation_client_->IsValidRequest(request) : 1);
1454 return request;
1455 }
1456
1457 bool ChromeFrameNPAPI::HandleContextMenuCommand(UINT cmd) {
1458 if (cmd == IDC_ABOUT_CHROME_FRAME) {
1459 // TODO: implement "About Chrome Frame"
1460 }
1461 return false;
1462 }
OLDNEW
« no previous file with comments | « chrome_frame/chrome_frame_npapi.h ('k') | chrome_frame/chrome_frame_npapi.rgs » ('j') | no next file with comments »

Powered by Google App Engine