OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2009, Google Inc. | 2 * Copyright 2009, Google Inc. |
3 * All rights reserved. | 3 * All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
7 * met: | 7 * met: |
8 * | 8 * |
9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 21 matching lines...) Expand all Loading... |
32 | 32 |
33 // This file implements the platform specific parts of the plugin for | 33 // This file implements the platform specific parts of the plugin for |
34 // the Windows platform. | 34 // the Windows platform. |
35 | 35 |
36 #include "plugin/cross/main.h" | 36 #include "plugin/cross/main.h" |
37 | 37 |
38 #include <windows.h> | 38 #include <windows.h> |
39 #include <windowsx.h> | 39 #include <windowsx.h> |
40 #include <shellapi.h> | 40 #include <shellapi.h> |
41 | 41 |
42 #include "base/at_exit.h" | |
43 #include "base/command_line.h" | |
44 #include "base/file_util.h" | |
45 #include "base/logging.h" | 42 #include "base/logging.h" |
46 #include "base/ref_counted.h" | |
47 #include "core/cross/display_mode.h" | 43 #include "core/cross/display_mode.h" |
48 #include "core/cross/event.h" | 44 #include "core/cross/event.h" |
49 #include "plugin/cross/plugin_logging.h" | 45 #include "core/win/display_window_win.h" |
50 #include "plugin/cross/out_of_memory.h" | |
51 #include "plugin/cross/whitelist.h" | |
52 #include "statsreport/metrics.h" | |
53 #include "v8/include/v8.h" | 46 #include "v8/include/v8.h" |
54 #include "breakpad/win/bluescreen_detector.h" | 47 #if !defined(O3D_INTERNAL_PLUGIN) |
| 48 #include "breakpad/win/exception_handler_win32.h" |
| 49 #endif |
55 | 50 |
56 using glue::_o3d::PluginObject; | 51 using glue::_o3d::PluginObject; |
57 using glue::StreamManager; | 52 using glue::StreamManager; |
58 using o3d::DisplayWindowWindows; | 53 using o3d::DisplayWindowWindows; |
59 using o3d::Event; | 54 using o3d::Event; |
60 | 55 |
61 namespace { | 56 namespace { |
62 // The instance handle of the O3D DLL. | 57 // The instance handle of the O3D DLL. |
63 HINSTANCE g_module_instance; | 58 HINSTANCE g_module_instance; |
64 } // namespace anonymous | 59 } // namespace anonymous |
65 | 60 |
66 #if !defined(O3D_INTERNAL_PLUGIN) | 61 #if !defined(O3D_INTERNAL_PLUGIN) |
67 | 62 // Used for breakpad crash handling |
68 o3d::PluginLogging* g_logger = NULL; | 63 static ExceptionManager *g_exception_manager = NULL; |
69 bool g_logging_initialized = false; | |
70 o3d::BluescreenDetector *g_bluescreen_detector = NULL; | |
71 | 64 |
72 extern "C" BOOL WINAPI DllMain(HINSTANCE instance, | 65 extern "C" BOOL WINAPI DllMain(HINSTANCE instance, |
73 DWORD reason, | 66 DWORD reason, |
74 LPVOID reserved) { | 67 LPVOID reserved) { |
75 g_module_instance = instance; | 68 g_module_instance = instance; |
76 | 69 |
77 if (reason == DLL_PROCESS_DETACH) { | 70 if (reason == DLL_PROCESS_DETACH) { |
78 // Teardown V8 when the plugin dll is unloaded. | 71 // Teardown V8 when the plugin dll is unloaded. |
79 // NOTE: NP_Shutdown would have been a good place for this code but | 72 // NOTE: NP_Shutdown would have been a good place for this code but |
80 // unfortunately it looks like it gets called even when the dll | 73 // unfortunately it looks like it gets called even when the dll |
81 // isn't really unloaded. This is a problem since after calling | 74 // isn't really unloaded. This is a problem since after calling |
82 // V8::Dispose(), V8 cannot be initialized again. | 75 // V8::Dispose(), V8 cannot be initialized again. |
83 bool v8_disposed = v8::V8::Dispose(); | 76 bool v8_disposed = v8::V8::Dispose(); |
84 if (!v8_disposed) | 77 if (!v8_disposed) |
85 DLOG(ERROR) << "Failed to release V8 resources."; | 78 DLOG(ERROR) << "Failed to release V8 resources."; |
86 return true; | 79 return true; |
87 } | 80 } |
88 return true; | 81 return true; |
89 } | 82 } |
90 #endif // O3D_INTERNAL_PLUGIN | 83 #endif // O3D_INTERNAL_PLUGIN |
91 | 84 |
92 namespace { | 85 namespace { |
93 const wchar_t* const kO3DWindowClassName = L"O3DWindowClass"; | 86 const wchar_t* const kO3DWindowClassName = L"O3DWindowClass"; |
94 | 87 |
95 void CleanupAllWindows(PluginObject *obj); | 88 void CleanupAllWindows(PluginObject *obj); |
96 | 89 |
97 // We would normally make this a stack variable in main(), but in a | |
98 // plugin, that's not possible, so we make it a global. When the DLL is loaded | |
99 // this it gets constructed and when it is unlooaded it is destructed. Note | |
100 // that this cannot be done in NP_Initialize and NP_Shutdown because those | |
101 // calls do not necessarily signify the DLL being loaded and unloaded. If the | |
102 // DLL is not unloaded then the values of global variables are preserved. | |
103 base::AtExitManager g_at_exit_manager; | |
104 | |
105 static int HandleKeyboardEvent(PluginObject *obj, | 90 static int HandleKeyboardEvent(PluginObject *obj, |
106 HWND hWnd, | 91 HWND hWnd, |
107 UINT Msg, | 92 UINT Msg, |
108 WPARAM wParam, | 93 WPARAM wParam, |
109 LPARAM lParam) { | 94 LPARAM lParam) { |
110 DCHECK(obj); | 95 DCHECK(obj); |
111 DCHECK(obj->client()); | 96 DCHECK(obj->client()); |
112 Event::Type type; | 97 Event::Type type; |
113 // First figure out which kind of event to create, and do any event-specific | 98 // First figure out which kind of event to create, and do any event-specific |
114 // processing that can be done prior to creating it. | 99 // processing that can be done prior to creating it. |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 // Tell windows we don't need the background cleared. | 459 // Tell windows we don't need the background cleared. |
475 return 1; | 460 return 1; |
476 } | 461 } |
477 | 462 |
478 case WM_TIMER: { | 463 case WM_TIMER: { |
479 if (reentrance_count.get() > 1) { | 464 if (reentrance_count.get() > 1) { |
480 break; // Ignore this message; we're reentrant. | 465 break; // Ignore this message; we're reentrant. |
481 } | 466 } |
482 | 467 |
483 #if !defined(O3D_INTERNAL_PLUGIN) | 468 #if !defined(O3D_INTERNAL_PLUGIN) |
484 // TODO: Only logging for windows until we figure out the proper | |
485 // mac way | |
486 if (g_logger) g_logger->UpdateLogging(); | 469 if (g_logger) g_logger->UpdateLogging(); |
487 #endif | 470 #endif |
488 | 471 |
489 // If rendering continuously, invalidate the window and force a paint if | 472 // If rendering continuously, invalidate the window and force a paint if |
490 // it is visible. The paint invalidates the renderer and Tick will later | 473 // it is visible. The paint invalidates the renderer and Tick will later |
491 // repaint the window. | 474 // repaint the window. |
492 if (obj->client()->NeedsContinuousRender()) { | 475 if (obj->client()->NeedsContinuousRender()) { |
493 InvalidateRect(obj->GetHWnd(), NULL, FALSE); | 476 InvalidateRect(obj->GetHWnd(), NULL, FALSE); |
494 UpdateWindow(obj->GetHWnd()); | 477 UpdateWindow(obj->GetHWnd()); |
495 } | 478 } |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
646 window_class.lpszClassName = kO3DWindowClassName; | 629 window_class.lpszClassName = kO3DWindowClassName; |
647 // We use CS_OWNDC in case we are rendering OpenGL into this window. | 630 // We use CS_OWNDC in case we are rendering OpenGL into this window. |
648 window_class.style = CS_DBLCLKS | CS_OWNDC; | 631 window_class.style = CS_DBLCLKS | CS_OWNDC; |
649 return RegisterClassEx(&window_class) != 0; | 632 return RegisterClassEx(&window_class) != 0; |
650 } | 633 } |
651 | 634 |
652 void UnregisterO3DWindowClass() { | 635 void UnregisterO3DWindowClass() { |
653 UnregisterClass(kO3DWindowClassName, g_module_instance); | 636 UnregisterClass(kO3DWindowClassName, g_module_instance); |
654 } | 637 } |
655 | 638 |
656 NPError InitializePlugin() { | |
657 #if !defined(O3D_INTERNAL_PLUGIN) | |
658 if (!o3d::SetupOutOfMemoryHandler()) | |
659 return NPERR_MODULE_LOAD_FAILED_ERROR; | |
660 | |
661 // Setup crash handler | |
662 if (!g_exception_manager) { | |
663 g_exception_manager = new ExceptionManager(false); | |
664 g_exception_manager->StartMonitoring(); | |
665 } | |
666 | |
667 // Turn on the logging. | |
668 CommandLine::Init(0, NULL); | |
669 | |
670 FilePath log; | |
671 file_util::GetTempDir(&log); | |
672 log.Append(L"debug.log"); | |
673 | |
674 InitLogging(log.value().c_str(), | |
675 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG, | |
676 logging::DONT_LOCK_LOG_FILE, | |
677 logging::APPEND_TO_OLD_LOG_FILE); | |
678 #endif // O3D_INTERNAL_PLUGIN | |
679 | |
680 DLOG(INFO) << "NP_Initialize"; | |
681 | |
682 if (!RegisterO3DWindowClass()) | |
683 return NPERR_MODULE_LOAD_FAILED_ERROR; | |
684 | |
685 return NPERR_NO_ERROR; | |
686 } | |
687 | |
688 void CleanupAllWindows(PluginObject *obj) { | 639 void CleanupAllWindows(PluginObject *obj) { |
689 if (obj->GetContentHWnd()) { | 640 if (obj->GetContentHWnd()) { |
690 ::KillTimer(obj->GetContentHWnd(), 0); | 641 ::KillTimer(obj->GetContentHWnd(), 0); |
691 PluginObject::ClearPluginProperty(obj->GetContentHWnd()); | 642 PluginObject::ClearPluginProperty(obj->GetContentHWnd()); |
692 ::PostMessage(obj->GetContentHWnd(), kDestroyWindowMessageID, 0, 0); | 643 ::PostMessage(obj->GetContentHWnd(), kDestroyWindowMessageID, 0, 0); |
693 obj->SetContentHWnd(NULL); | 644 obj->SetContentHWnd(NULL); |
694 } | 645 } |
695 | 646 |
696 if (obj->GetPluginHWnd()) { | 647 if (obj->GetPluginHWnd()) { |
697 // Restore the original WNDPROC on the plugin window so that we | 648 // Restore the original WNDPROC on the plugin window so that we |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 if (GetMonitorInfo(monitor, &monitor_info)) { | 696 if (GetMonitorInfo(monitor, &monitor_info)) { |
746 *rect = monitor_info.rcMonitor; | 697 *rect = monitor_info.rcMonitor; |
747 return true; | 698 return true; |
748 } else { | 699 } else { |
749 return false; | 700 return false; |
750 } | 701 } |
751 } | 702 } |
752 | 703 |
753 } // namespace anonymous | 704 } // namespace anonymous |
754 | 705 |
755 #if defined(O3D_INTERNAL_PLUGIN) | |
756 namespace o3d { | 706 namespace o3d { |
757 #else | |
758 extern "C" { | |
759 #endif | |
760 | 707 |
761 NPError OSCALL NP_Initialize(NPNetscapeFuncs *browserFuncs) { | 708 NPError PlatformPreNPInitialize() { |
762 HANDLE_CRASHES; | 709 #if !defined(O3D_INTERNAL_PLUGIN) |
763 | 710 // Setup crash handler |
764 NPError retval = InitializeNPNApi(browserFuncs); | 711 if (!g_exception_manager) { |
765 if (retval != NPERR_NO_ERROR) return retval; | 712 g_exception_manager = new ExceptionManager(false); |
766 return InitializePlugin(); | 713 g_exception_manager->StartMonitoring(); |
| 714 } |
| 715 #endif // O3D_INTERNAL_PLUGIN |
| 716 return NPERR_NO_ERROR; |
767 } | 717 } |
768 | 718 |
769 NPError OSCALL NP_Shutdown(void) { | 719 NPError PlatformPostNPInitialize() { |
770 HANDLE_CRASHES; | 720 if (!RegisterO3DWindowClass()) |
771 DLOG(INFO) << "NP_Shutdown"; | 721 return NPERR_MODULE_LOAD_FAILED_ERROR; |
772 | 722 |
| 723 return NPERR_NO_ERROR; |
| 724 } |
| 725 |
| 726 NPError PlatformPreNPShutdown() { |
| 727 // TODO(tschmelcher): Is there a reason we need to do this before the main |
| 728 // shutdown tasks? If not, we can axe the PlatformPreNPShutdown() function. |
773 UnregisterO3DWindowClass(); | 729 UnregisterO3DWindowClass(); |
| 730 return NPERR_NO_ERROR; |
| 731 } |
774 | 732 |
| 733 NPError PlatformPostNPShutdown() { |
775 #if !defined(O3D_INTERNAL_PLUGIN) | 734 #if !defined(O3D_INTERNAL_PLUGIN) |
776 | |
777 if (g_logger) { | |
778 // Do a last sweep to aggregate metrics before we shut down | |
779 g_logger->ProcessMetrics(true, false, false); | |
780 delete g_logger; | |
781 g_logger = NULL; | |
782 g_logging_initialized = false; | |
783 stats_report::g_global_metrics.Uninitialize(); | |
784 } | |
785 | |
786 CommandLine::Reset(); | |
787 | |
788 // TODO : This is commented out until we can determine if | 735 // TODO : This is commented out until we can determine if |
789 // it's safe to shutdown breakpad at this stage (Gears, for | 736 // it's safe to shutdown breakpad at this stage (Gears, for |
790 // example, never deletes...) | 737 // example, never deletes...) |
791 // Shutdown breakpad | 738 // Shutdown breakpad |
792 // delete g_exception_manager; | 739 // delete g_exception_manager; |
793 | |
794 // Strictly speaking, on windows, it's not really necessary to call | |
795 // Stop(), but we do so for completeness | |
796 if (g_bluescreen_detector) { | |
797 g_bluescreen_detector->Stop(); | |
798 delete g_bluescreen_detector; | |
799 g_bluescreen_detector = NULL; | |
800 } | |
801 | |
802 #endif // O3D_INTERNAL_PLUGIN | |
803 | |
804 return NPERR_NO_ERROR; | |
805 } | |
806 } // extern "C" / namespace o3d | |
807 | |
808 namespace o3d { | |
809 | |
810 NPError NPP_New(NPMIMEType pluginType, | |
811 NPP instance, | |
812 uint16 mode, | |
813 int16 argc, | |
814 char *argn[], | |
815 char *argv[], | |
816 NPSavedData *saved) { | |
817 HANDLE_CRASHES; | |
818 | |
819 #if !defined(O3D_INTERNAL_PLUGIN) | |
820 if (!g_logging_initialized) { | |
821 // Get user config metrics. These won't be stored though unless the user | |
822 // opts-in for usagestats logging | |
823 GetUserAgentMetrics(instance); | |
824 GetUserConfigMetrics(); | |
825 // Create usage stats logs object | |
826 g_logger = o3d::PluginLogging::InitializeUsageStatsLogging(); | |
827 if (g_logger) { | |
828 // Setup blue-screen detection | |
829 g_bluescreen_detector = new o3d::BluescreenDetector(); | |
830 g_bluescreen_detector->Start(); | |
831 } | |
832 g_logging_initialized = true; | |
833 } | |
834 #endif | 740 #endif |
835 | 741 |
836 if (!IsDomainAuthorized(instance)) { | |
837 return NPERR_INVALID_URL; | |
838 } | |
839 | |
840 PluginObject* pluginObject = glue::_o3d::PluginObject::Create( | |
841 instance); | |
842 instance->pdata = pluginObject; | |
843 glue::_o3d::InitializeGlue(instance); | |
844 pluginObject->Init(argc, argn, argv); | |
845 return NPERR_NO_ERROR; | |
846 } | |
847 | |
848 NPError NPP_Destroy(NPP instance, NPSavedData **save) { | |
849 HANDLE_CRASHES; | |
850 PluginObject *obj = static_cast<PluginObject*>(instance->pdata); | |
851 if (obj) { | |
852 if (obj->GetHWnd()) { | |
853 CleanupAllWindows(obj); | |
854 } | |
855 | |
856 obj->TearDown(); | |
857 NPN_ReleaseObject(obj); | |
858 instance->pdata = NULL; | |
859 } | |
860 | |
861 return NPERR_NO_ERROR; | 742 return NPERR_NO_ERROR; |
862 } | 743 } |
863 | 744 |
864 NPError PlatformNPPGetValue(NPP instance, NPPVariable variable, void *value) { | 745 NPError PlatformNPPNew(NPP instance, PluginObject *obj) { |
| 746 return NPERR_NO_ERROR; |
| 747 } |
| 748 |
| 749 NPError PlatformNPPDestroy(NPP instance, PluginObject *obj) { |
| 750 if (obj->GetHWnd()) { |
| 751 CleanupAllWindows(obj); |
| 752 } |
| 753 |
| 754 obj->TearDown(); |
| 755 return NPERR_NO_ERROR; |
| 756 } |
| 757 |
| 758 NPError PlatformNPPGetValue(PluginObject *obj, |
| 759 NPPVariable variable, |
| 760 void *value) { |
865 return NPERR_INVALID_PARAM; | 761 return NPERR_INVALID_PARAM; |
866 } | 762 } |
867 | 763 |
868 NPError NPP_SetWindow(NPP instance, NPWindow *window) { | 764 NPError PlatformNPPSetWindow(NPP instance, |
869 HANDLE_CRASHES; | 765 PluginObject *obj, |
870 PluginObject *obj = static_cast<PluginObject*>(instance->pdata); | 766 NPWindow *window) { |
871 | |
872 HWND hWnd = static_cast<HWND>(window->window); | 767 HWND hWnd = static_cast<HWND>(window->window); |
873 if (!hWnd) { | 768 if (!hWnd) { |
874 // Chrome calls us this way before NPP_Destroy. | 769 // Chrome calls us this way before NPP_Destroy. |
875 if (obj->GetHWnd()) { | 770 if (obj->GetHWnd()) { |
876 CleanupAllWindows(obj); | 771 CleanupAllWindows(obj); |
877 } | 772 } |
878 return NPERR_NO_ERROR; | 773 return NPERR_NO_ERROR; |
879 } | 774 } |
880 | 775 |
881 if (obj->GetPluginHWnd() == hWnd) { | 776 if (obj->GetPluginHWnd() == hWnd) { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
941 obj->client()->Init(); | 836 obj->client()->Init(); |
942 | 837 |
943 // we set the timer to 10ms or 100fps. At the time of this comment | 838 // we set the timer to 10ms or 100fps. At the time of this comment |
944 // the renderer does a vsync the max fps it will run will be the refresh | 839 // the renderer does a vsync the max fps it will run will be the refresh |
945 // rate of the monitor or 100fps, which ever is lower. | 840 // rate of the monitor or 100fps, which ever is lower. |
946 ::SetTimer(obj->GetHWnd(), 0, 10, NULL); | 841 ::SetTimer(obj->GetHWnd(), 0, 10, NULL); |
947 | 842 |
948 return NPERR_NO_ERROR; | 843 return NPERR_NO_ERROR; |
949 } | 844 } |
950 | 845 |
951 // Called when the browser has finished attempting to stream data to | 846 void PlatformNPPStreamAsFile(StreamManager *stream_manager, |
952 // a file as requested. If fname == NULL the attempt was not successful. | 847 NPStream *stream, |
953 void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) { | 848 const char *fname) { |
954 HANDLE_CRASHES; | |
955 PluginObject *obj = static_cast<PluginObject*>(instance->pdata); | |
956 StreamManager *stream_manager = obj->stream_manager(); | |
957 | |
958 stream_manager->SetStreamFile(stream, fname); | 849 stream_manager->SetStreamFile(stream, fname); |
959 } | 850 } |
960 | 851 |
961 int16 NPP_HandleEvent(NPP instance, void *event) { | 852 int16 PlatformNPPHandleEvent(NPP instance, PluginObject *obj, void *event) { |
962 HANDLE_CRASHES; | |
963 return 0; | 853 return 0; |
964 } | 854 } |
| 855 |
965 } // namespace o3d | 856 } // namespace o3d |
966 | 857 |
| 858 // TODO(tschmelcher): This stuff does not belong in this file. |
967 namespace glue { | 859 namespace glue { |
968 namespace _o3d { | 860 namespace _o3d { |
969 bool PluginObject::GetDisplayMode(int mode_id, o3d::DisplayMode *mode) { | 861 bool PluginObject::GetDisplayMode(int mode_id, o3d::DisplayMode *mode) { |
970 return renderer()->GetDisplayMode(mode_id, mode); | 862 return renderer()->GetDisplayMode(mode_id, mode); |
971 } | 863 } |
972 | 864 |
973 // TODO: Where should this really live? It's platform-specific, but in | 865 // TODO: Where should this really live? It's platform-specific, but in |
974 // PluginObject, which mainly lives in cross/o3d_glue.h+cc. | 866 // PluginObject, which mainly lives in cross/o3d_glue.h+cc. |
975 bool PluginObject::RequestFullscreenDisplay() { | 867 bool PluginObject::RequestFullscreenDisplay() { |
976 bool success = false; | 868 bool success = false; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1035 if (!renderer_->CancelFullscreen(display, prev_width_, prev_height_)) { | 927 if (!renderer_->CancelFullscreen(display, prev_width_, prev_height_)) { |
1036 LOG(FATAL) << "Failed to get the renderer out of fullscreen mode!"; | 928 LOG(FATAL) << "Failed to get the renderer out of fullscreen mode!"; |
1037 } | 929 } |
1038 ReplaceContentWindow(GetContentHWnd(), GetPluginHWnd(), | 930 ReplaceContentWindow(GetContentHWnd(), GetPluginHWnd(), |
1039 prev_width_, prev_height_); | 931 prev_width_, prev_height_); |
1040 client()->SendResizeEvent(prev_width_, prev_height_, false); | 932 client()->SendResizeEvent(prev_width_, prev_height_, false); |
1041 } | 933 } |
1042 } | 934 } |
1043 } // namespace _o3d | 935 } // namespace _o3d |
1044 } // namespace glue | 936 } // namespace glue |
OLD | NEW |