| 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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 | 52 |
| 53 using glue::_o3d::PluginObject; | 53 using glue::_o3d::PluginObject; |
| 54 using glue::StreamManager; | 54 using glue::StreamManager; |
| 55 using o3d::DisplayWindowWindows; | 55 using o3d::DisplayWindowWindows; |
| 56 using o3d::Event; | 56 using o3d::Event; |
| 57 | 57 |
| 58 o3d::PluginLogging* g_logger = NULL; | 58 o3d::PluginLogging* g_logger = NULL; |
| 59 bool g_logging_initialized = false; | 59 bool g_logging_initialized = false; |
| 60 o3d::BluescreenDetector *g_bluescreen_detector = NULL; | 60 o3d::BluescreenDetector *g_bluescreen_detector = NULL; |
| 61 | 61 |
| 62 #if !defined(O3D_INTERNAL_PLUGIN) |
| 63 extern "C" BOOL WINAPI DllMain(HINSTANCE instance, |
| 64 DWORD reason, |
| 65 LPVOID reserved) { |
| 66 if (reason == DLL_PROCESS_DETACH) { |
| 67 // Teardown V8 when the plugin dll is unloaded. |
| 68 // NOTE: NP_Shutdown would have been a good place for this code but |
| 69 // unfortunately it looks like it gets called even when the dll |
| 70 // isn't really unloaded. This is a problem since after calling |
| 71 // V8::Dispose(), V8 cannot be initialized again. |
| 72 bool v8_disposed = v8::V8::Dispose(); |
| 73 if (!v8_disposed) |
| 74 DLOG(ERROR) << "Failed to release V8 resources."; |
| 75 return true; |
| 76 } |
| 77 return true; |
| 78 } |
| 79 #endif // O3D_INTERNAL_PLUGIN |
| 80 |
| 62 namespace { | 81 namespace { |
| 63 // We would normally make this a stack variable in main(), but in a | 82 // We would normally make this a stack variable in main(), but in a |
| 64 // plugin, that's not possible, so we allocate it dynamically and | 83 // plugin, that's not possible, so we allocate it dynamically and |
| 65 // destroy it explicitly. | 84 // destroy it explicitly. |
| 66 scoped_ptr<base::AtExitManager> g_at_exit_manager; | 85 scoped_ptr<base::AtExitManager> g_at_exit_manager; |
| 67 } // end anonymous namespace | |
| 68 | |
| 69 void RenderOnDemandCallbackHandler::Run() { | |
| 70 ::InvalidateRect(obj_->GetHWnd(), NULL, TRUE); | |
| 71 } | |
| 72 | 86 |
| 73 static int HandleKeyboardEvent(PluginObject *obj, | 87 static int HandleKeyboardEvent(PluginObject *obj, |
| 74 HWND hWnd, | 88 HWND hWnd, |
| 75 UINT Msg, | 89 UINT Msg, |
| 76 WPARAM wParam, | 90 WPARAM wParam, |
| 77 LPARAM lParam) { | 91 LPARAM lParam) { |
| 78 DCHECK(obj); | 92 DCHECK(obj); |
| 79 DCHECK(obj->client()); | 93 DCHECK(obj->client()); |
| 80 Event::Type type; | 94 Event::Type type; |
| 81 // First figure out which kind of event to create, and do any event-specific | 95 // First figure out which kind of event to create, and do any event-specific |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 if (event.type() == Event::TYPE_KEYDOWN && | 155 if (event.type() == Event::TYPE_KEYDOWN && |
| 142 (wParam == VK_ESCAPE || | 156 (wParam == VK_ESCAPE || |
| 143 (wParam == VK_F4 && (modifier_state & Event::MODIFIER_ALT)))) { | 157 (wParam == VK_F4 && (modifier_state & Event::MODIFIER_ALT)))) { |
| 144 obj->CancelFullscreenDisplay(); | 158 obj->CancelFullscreenDisplay(); |
| 145 } | 159 } |
| 146 | 160 |
| 147 obj->client()->AddEventToQueue(event); | 161 obj->client()->AddEventToQueue(event); |
| 148 return 0; | 162 return 0; |
| 149 } | 163 } |
| 150 | 164 |
| 151 static void HandleMouseEvent(PluginObject *obj, | 165 void HandleMouseEvent(PluginObject *obj, |
| 152 HWND hWnd, | 166 HWND hWnd, |
| 153 UINT Msg, | 167 UINT Msg, |
| 154 WPARAM wParam, | 168 WPARAM wParam, |
| 155 LPARAM lParam) { | 169 LPARAM lParam) { |
| 156 DCHECK(obj); | 170 DCHECK(obj); |
| 157 DCHECK(obj->client()); | 171 DCHECK(obj->client()); |
| 158 bool fake_dblclick = false; | 172 bool fake_dblclick = false; |
| 159 Event::Type type; | 173 Event::Type type; |
| 160 int x = GET_X_LPARAM(lParam); | 174 int x = GET_X_LPARAM(lParam); |
| 161 int y = GET_Y_LPARAM(lParam); | 175 int y = GET_Y_LPARAM(lParam); |
| 162 int screen_x, screen_y; | 176 int screen_x, screen_y; |
| 163 bool in_plugin = false; | 177 bool in_plugin = false; |
| 164 { | 178 { |
| 165 RECT rect; | 179 RECT rect; |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 event.set_type(Event::TYPE_DBLCLICK); | 333 event.set_type(Event::TYPE_DBLCLICK); |
| 320 obj->client()->AddEventToQueue(event); | 334 obj->client()->AddEventToQueue(event); |
| 321 } | 335 } |
| 322 if (in_plugin && type == Event::TYPE_MOUSEDOWN && | 336 if (in_plugin && type == Event::TYPE_MOUSEDOWN && |
| 323 obj->HitFullscreenClickRegion(x, y)) { | 337 obj->HitFullscreenClickRegion(x, y)) { |
| 324 obj->RequestFullscreenDisplay(); | 338 obj->RequestFullscreenDisplay(); |
| 325 } | 339 } |
| 326 } | 340 } |
| 327 | 341 |
| 328 // This returns 0 on success, 1 on failure, to match WindowProc. | 342 // This returns 0 on success, 1 on failure, to match WindowProc. |
| 329 static LRESULT ForwardEvent(PluginObject *obj, | 343 LRESULT ForwardEvent(PluginObject *obj, |
| 330 HWND hWnd, | 344 HWND hWnd, |
| 331 UINT Msg, | 345 UINT Msg, |
| 332 WPARAM wParam, | 346 WPARAM wParam, |
| 333 LPARAM lParam, | 347 LPARAM lParam, |
| 334 bool translateCoords) { | 348 bool translateCoords) { |
| 335 DCHECK(obj); | 349 DCHECK(obj); |
| 336 DCHECK(obj->GetPluginHWnd()); | 350 DCHECK(obj->GetPluginHWnd()); |
| 337 HWND dest_hwnd = obj->GetParentHWnd(); | 351 HWND dest_hwnd = obj->GetParentHWnd(); |
| 338 DCHECK(hWnd); | 352 DCHECK(hWnd); |
| 339 DCHECK(dest_hwnd); | 353 DCHECK(dest_hwnd); |
| 340 bool fullscreen = hWnd == obj->GetFullscreenHWnd(); | 354 bool fullscreen = hWnd == obj->GetFullscreenHWnd(); |
| 341 if (fullscreen) { | 355 if (fullscreen) { |
| 342 dest_hwnd = obj->GetPluginHWnd(); | 356 dest_hwnd = obj->GetPluginHWnd(); |
| 343 } else if (obj->IsChrome()) { | 357 } else if (obj->IsChrome()) { |
| 344 // When trying to find the parent window of the Chrome plugin, new Chrome is | 358 // When trying to find the parent window of the Chrome plugin, new Chrome is |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 // The plugin and the fullscreen window each fill their respective entire | 405 // The plugin and the fullscreen window each fill their respective entire |
| 392 // window, so there aren't any offsets to add or subtract. | 406 // window, so there aren't any offsets to add or subtract. |
| 393 y_1 = y * height_1 / height; | 407 y_1 = y * height_1 / height; |
| 394 } | 408 } |
| 395 | 409 |
| 396 lParam = MAKELPARAM(x_1, y_1); | 410 lParam = MAKELPARAM(x_1, y_1); |
| 397 } | 411 } |
| 398 return !::PostMessage(dest_hwnd, Msg, wParam, lParam); | 412 return !::PostMessage(dest_hwnd, Msg, wParam, lParam); |
| 399 } | 413 } |
| 400 | 414 |
| 401 static LRESULT HandleDragAndDrop(PluginObject *obj, WPARAM wParam) { | 415 LRESULT HandleDragAndDrop(PluginObject *obj, WPARAM wParam) { |
| 402 HDROP hDrop = reinterpret_cast<HDROP>(wParam); | 416 HDROP hDrop = reinterpret_cast<HDROP>(wParam); |
| 403 UINT num_files = ::DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); | 417 UINT num_files = ::DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); |
| 404 if (!num_files) { | 418 if (!num_files) { |
| 405 ::DragFinish(hDrop); | 419 ::DragFinish(hDrop); |
| 406 return 0; | 420 return 0; |
| 407 } | 421 } |
| 408 UINT path_len = ::DragQueryFile(hDrop, 0, NULL, 0); | 422 UINT path_len = ::DragQueryFile(hDrop, 0, NULL, 0); |
| 409 // Let's limit that length, just in case. | 423 // Let's limit that length, just in case. |
| 410 if (!path_len || path_len > 4096) { | 424 if (!path_len || path_len > 4096) { |
| 411 ::DragFinish(hDrop); | 425 ::DragFinish(hDrop); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 450 for (UINT i = 0; i < num_chars; ++i) { | 464 for (UINT i = 0; i < num_chars; ++i) { |
| 451 if (path_to_use[i] == '\\') { | 465 if (path_to_use[i] == '\\') { |
| 452 path_to_use[i] = '/'; | 466 path_to_use[i] = '/'; |
| 453 } | 467 } |
| 454 } | 468 } |
| 455 obj->RedirectToFile(path_to_use); | 469 obj->RedirectToFile(path_to_use); |
| 456 | 470 |
| 457 return 1; | 471 return 1; |
| 458 } | 472 } |
| 459 | 473 |
| 460 static LRESULT CALLBACK | 474 LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { |
| 461 WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { | |
| 462 PluginObject *obj = PluginObject::GetPluginProperty(hWnd); | 475 PluginObject *obj = PluginObject::GetPluginProperty(hWnd); |
| 463 if (obj == NULL) { // It's not my window | 476 if (obj == NULL) { // It's not my window |
| 464 return 1; // 0 often means we handled it. | 477 return 1; // 0 often means we handled it. |
| 465 } | 478 } |
| 466 | 479 |
| 467 // Limit the ways in which we can be reentrant. Note that this WindowProc | 480 // Limit the ways in which we can be reentrant. Note that this WindowProc |
| 468 // may be called by different threads. For example, IE will register plugin | 481 // may be called by different threads. For example, IE will register plugin |
| 469 // instances on separate threads. | 482 // instances on separate threads. |
| 470 o3d::Client::ScopedIncrement reentrance_count(obj->client()); | 483 o3d::Client::ScopedIncrement reentrance_count(obj->client()); |
| 471 | 484 |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 637 return ::CallWindowProc(obj->GetDefaultPluginWindowProc(), | 650 return ::CallWindowProc(obj->GetDefaultPluginWindowProc(), |
| 638 hWnd, | 651 hWnd, |
| 639 Msg, | 652 Msg, |
| 640 wParam, | 653 wParam, |
| 641 lParam); | 654 lParam); |
| 642 } | 655 } |
| 643 } | 656 } |
| 644 return 0; | 657 return 0; |
| 645 } | 658 } |
| 646 | 659 |
| 660 NPError InitializePlugin() { |
| 661 #if !defined(O3D_INTERNAL_PLUGIN) |
| 662 if (!o3d::SetupOutOfMemoryHandler()) |
| 663 return NPERR_MODULE_LOAD_FAILED_ERROR; |
| 664 |
| 665 // Setup crash handler |
| 666 if (!g_exception_manager) { |
| 667 g_exception_manager = new ExceptionManager(false); |
| 668 g_exception_manager->StartMonitoring(); |
| 669 } |
| 670 |
| 671 // Initialize the AtExitManager so that base singletons can be |
| 672 // destroyed properly. |
| 673 g_at_exit_manager.reset(new base::AtExitManager()); |
| 674 |
| 675 // Turn on the logging. |
| 676 CommandLine::Init(0, NULL); |
| 677 InitLogging(L"debug.log", |
| 678 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG, |
| 679 logging::DONT_LOCK_LOG_FILE, |
| 680 logging::APPEND_TO_OLD_LOG_FILE); |
| 681 #endif // O3D_INTERNAL_PLUGIN |
| 682 |
| 683 DLOG(INFO) << "NP_Initialize"; |
| 684 |
| 685 return NPERR_NO_ERROR; |
| 686 } |
| 687 |
| 688 void CleanupFullscreenWindow(PluginObject *obj) { |
| 689 DCHECK(obj->GetFullscreenHWnd()); |
| 690 obj->StorePluginProperty(obj->GetPluginHWnd(), obj); |
| 691 ::DestroyWindow(obj->GetFullscreenHWnd()); |
| 692 obj->SetFullscreenHWnd(NULL); |
| 693 } |
| 694 |
| 695 void CleanupAllWindows(PluginObject *obj) { |
| 696 DCHECK(obj->GetHWnd()); |
| 697 DCHECK(obj->GetPluginHWnd()); |
| 698 ::KillTimer(obj->GetHWnd(), 0); |
| 699 if (obj->GetFullscreenHWnd()) { |
| 700 CleanupFullscreenWindow(obj); |
| 701 } |
| 702 PluginObject::ClearPluginProperty(obj->GetHWnd()); |
| 703 ::SetWindowLongPtr(obj->GetPluginHWnd(), |
| 704 GWL_WNDPROC, |
| 705 reinterpret_cast<LONG_PTR>( |
| 706 obj->GetDefaultPluginWindowProc())); |
| 707 obj->SetPluginHWnd(NULL); |
| 708 obj->SetHWnd(NULL); |
| 709 } |
| 710 |
| 711 HWND CreateFullscreenWindow(PluginObject *obj, |
| 712 int mode_id) { |
| 713 o3d::DisplayMode mode; |
| 714 if (!obj->renderer()->GetDisplayMode(mode_id, &mode)) { |
| 715 return NULL; |
| 716 } |
| 717 CHECK(mode.width() > 0 && mode.height() > 0); |
| 718 |
| 719 HINSTANCE instance = |
| 720 reinterpret_cast<HINSTANCE>( |
| 721 ::GetWindowLongPtr(obj->GetPluginHWnd(), GWLP_HINSTANCE)); |
| 722 WNDCLASSEX *wcx = obj->GetFullscreenWindowClass(instance, WindowProc); |
| 723 HWND hWnd = CreateWindowEx(NULL, |
| 724 wcx->lpszClassName, |
| 725 L"O3D Test Fullscreen Window", |
| 726 WS_POPUP, |
| 727 0, 0, |
| 728 mode.width(), |
| 729 mode.height(), |
| 730 NULL, |
| 731 NULL, |
| 732 instance, |
| 733 NULL); |
| 734 |
| 735 ShowWindow(hWnd, SW_SHOW); |
| 736 return hWnd; |
| 737 } |
| 738 } // namespace anonymous |
| 739 |
| 740 #if defined(O3D_INTERNAL_PLUGIN) |
| 741 namespace o3d { |
| 742 #else |
| 743 extern "C" { |
| 744 #endif |
| 745 |
| 746 NPError OSCALL NP_Initialize(NPNetscapeFuncs *browserFuncs) { |
| 747 HANDLE_CRASHES; |
| 748 NPError retval = InitializeNPNApi(browserFuncs); |
| 749 if (retval != NPERR_NO_ERROR) return retval; |
| 750 return InitializePlugin(); |
| 751 } |
| 752 |
| 753 NPError OSCALL NP_Shutdown(void) { |
| 754 HANDLE_CRASHES; |
| 755 DLOG(INFO) << "NP_Shutdown"; |
| 756 |
| 757 #if !defined(O3D_INTERNAL_PLUGIN) |
| 758 |
| 759 if (g_logger) { |
| 760 // Do a last sweep to aggregate metrics before we shut down |
| 761 g_logger->ProcessMetrics(true, false); |
| 762 delete g_logger; |
| 763 g_logger = NULL; |
| 764 g_logging_initialized = false; |
| 765 stats_report::g_global_metrics.Uninitialize(); |
| 766 } |
| 767 |
| 768 CommandLine::Terminate(); |
| 769 |
| 770 // Force all base singletons to be destroyed. |
| 771 g_at_exit_manager.reset(NULL); |
| 772 |
| 773 // TODO : This is commented out until we can determine if |
| 774 // it's safe to shutdown breakpad at this stage (Gears, for |
| 775 // example, never deletes...) |
| 776 // Shutdown breakpad |
| 777 // delete g_exception_manager; |
| 778 |
| 779 // Strictly speaking, on windows, it's not really necessary to call |
| 780 // Stop(), but we do so for completeness |
| 781 if (g_bluescreen_detector) { |
| 782 g_bluescreen_detector->Stop(); |
| 783 delete g_bluescreen_detector; |
| 784 g_bluescreen_detector = NULL; |
| 785 } |
| 786 |
| 787 #endif // O3D_INTERNAL_PLUGIN |
| 788 |
| 789 return NPERR_NO_ERROR; |
| 790 } |
| 791 } // extern "C" / namespace o3d |
| 792 |
| 793 namespace o3d { |
| 794 void RenderOnDemandCallbackHandler::Run() { |
| 795 ::InvalidateRect(obj_->GetHWnd(), NULL, TRUE); |
| 796 } |
| 797 |
| 798 NPError NPP_New(NPMIMEType pluginType, |
| 799 NPP instance, |
| 800 uint16 mode, |
| 801 int16 argc, |
| 802 char *argn[], |
| 803 char *argv[], |
| 804 NPSavedData *saved) { |
| 805 HANDLE_CRASHES; |
| 806 |
| 807 if (!g_logging_initialized) { |
| 808 // Get user config metrics. These won't be stored though unless the user |
| 809 // opts-in for usagestats logging |
| 810 GetUserAgentMetrics(instance); |
| 811 GetUserConfigMetrics(); |
| 812 // Create usage stats logs object |
| 813 g_logger = o3d::PluginLogging::InitializeUsageStatsLogging(); |
| 814 if (g_logger) { |
| 815 // Setup blue-screen detection |
| 816 g_bluescreen_detector = new o3d::BluescreenDetector(); |
| 817 g_bluescreen_detector->Start(); |
| 818 } |
| 819 g_logging_initialized = true; |
| 820 } |
| 821 PluginObject* pluginObject = glue::_o3d::PluginObject::Create( |
| 822 instance); |
| 823 instance->pdata = pluginObject; |
| 824 glue::_o3d::InitializeGlue(instance); |
| 825 pluginObject->Init(argc, argn, argv); |
| 826 return NPERR_NO_ERROR; |
| 827 } |
| 828 |
| 829 NPError NPP_Destroy(NPP instance, NPSavedData **save) { |
| 830 HANDLE_CRASHES; |
| 831 PluginObject *obj = static_cast<PluginObject*>(instance->pdata); |
| 832 if (obj) { |
| 833 if (obj->GetHWnd()) { |
| 834 CleanupAllWindows(obj); |
| 835 } |
| 836 |
| 837 obj->TearDown(); |
| 838 NPN_ReleaseObject(obj); |
| 839 instance->pdata = NULL; |
| 840 } |
| 841 |
| 842 return NPERR_NO_ERROR; |
| 843 } |
| 844 |
| 647 NPError PlatformNPPGetValue(NPP instance, NPPVariable variable, void *value) { | 845 NPError PlatformNPPGetValue(NPP instance, NPPVariable variable, void *value) { |
| 648 return NPERR_INVALID_PARAM; | 846 return NPERR_INVALID_PARAM; |
| 649 } | 847 } |
| 650 | 848 |
| 651 extern "C" { | 849 NPError NPP_SetWindow(NPP instance, NPWindow *window) { |
| 652 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { | 850 HANDLE_CRASHES; |
| 653 if (reason == DLL_PROCESS_DETACH) { | 851 PluginObject *obj = static_cast<PluginObject*>(instance->pdata); |
| 654 // Teardown V8 when the plugin dll is unloaded. | 852 |
| 655 // NOTE: NP_Shutdown would have been a good place for this code but | 853 HWND hWnd = static_cast<HWND>(window->window); |
| 656 // unfortunately it looks like it gets called even when the dll | 854 if (!hWnd) { |
| 657 // isn't really unloaded. This is a problem since after calling | 855 // Chrome calls us this way before NPP_Destroy. |
| 658 // V8::Dispose(), V8 cannot be initialized again. | 856 if (obj->GetHWnd()) { |
| 659 bool v8_disposed = v8::V8::Dispose(); | 857 CleanupAllWindows(obj); |
| 660 if (!v8_disposed) | 858 } |
| 661 DLOG(ERROR) << "Failed to release V8 resources."; | 859 return NPERR_NO_ERROR; |
| 662 return true; | 860 } |
| 663 } | 861 if (obj->GetHWnd() == hWnd) { |
| 664 return true; | 862 return NPERR_NO_ERROR; |
| 665 } | 863 } |
| 666 | 864 if (obj->fullscreen()) { |
| 667 NPError InitializePlugin() { | 865 // We can get here if the user alt+tabs away from the fullscreen plugin |
| 668 if (!o3d::SetupOutOfMemoryHandler()) | 866 // window or JavaScript resizes the plugin window. |
| 669 return NPERR_MODULE_LOAD_FAILED_ERROR; | 867 DCHECK(obj->GetPluginHWnd()); |
| 670 | 868 DCHECK(obj->GetFullscreenHWnd()); |
| 671 // Setup crash handler | 869 DCHECK(obj->GetPluginHWnd() == hWnd); |
| 672 if (!g_exception_manager) { | 870 return NPERR_NO_ERROR; |
| 673 g_exception_manager = new ExceptionManager(false); | 871 } |
| 674 g_exception_manager->StartMonitoring(); | 872 DCHECK(!obj->GetPluginHWnd()); |
| 675 } | 873 obj->SetPluginHWnd(hWnd); |
| 676 | 874 obj->SetParentHWnd(::GetParent(hWnd)); |
| 677 // Initialize the AtExitManager so that base singletons can be | 875 PluginObject::StorePluginProperty(hWnd, obj); |
| 678 // destroyed properly. | 876 obj->SetDefaultPluginWindowProc( |
| 679 g_at_exit_manager.reset(new base::AtExitManager()); | 877 reinterpret_cast<WNDPROC>( |
| 680 | 878 ::SetWindowLongPtr(hWnd, |
| 681 // Turn on the logging. | 879 GWL_WNDPROC, |
| 682 CommandLine::Init(0, NULL); | 880 reinterpret_cast<LONG_PTR>(WindowProc)))); |
| 683 InitLogging(L"debug.log", | 881 |
| 684 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG, | 882 // create and assign the graphics context |
| 685 logging::DONT_LOCK_LOG_FILE, | 883 DisplayWindowWindows default_display; |
| 686 logging::APPEND_TO_OLD_LOG_FILE); | 884 default_display.set_hwnd(obj->GetHWnd()); |
| 687 | 885 |
| 688 DLOG(INFO) << "NP_Initialize"; | 886 obj->CreateRenderer(default_display); |
| 689 | 887 obj->client()->Init(); |
| 690 // Limit the current thread to one processor (the current one). This ensures | 888 obj->client()->SetRenderOnDemandCallback( |
| 691 // that timing code runs on only one processor, and will not suffer any ill | 889 new RenderOnDemandCallbackHandler(obj)); |
| 692 // effects from power management. See "Game Timing and Multicore Processors" | 890 |
| 693 // in the DirectX docs for more details | 891 // we set the timer to 10ms or 100fps. At the time of this comment |
| 694 { | 892 // the renderer does a vsync the max fps it will run will be the refresh |
| 695 HANDLE current_process_handle = GetCurrentProcess(); | 893 // rate of the monitor or 100fps, which ever is lower. |
| 696 | 894 ::SetTimer(obj->GetHWnd(), 0, 10, NULL); |
| 697 // Get the processor affinity mask for this process | 895 |
| 698 DWORD_PTR process_affinity_mask = 0; | 896 return NPERR_NO_ERROR; |
| 699 DWORD_PTR system_affinity_mask = 0; | 897 } |
| 700 | 898 |
| 701 if (GetProcessAffinityMask(current_process_handle, | 899 // Called when the browser has finished attempting to stream data to |
| 702 &process_affinity_mask, | 900 // a file as requested. If fname == NULL the attempt was not successful. |
| 703 &system_affinity_mask) != 0 && | 901 void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) { |
| 704 process_affinity_mask) { | 902 HANDLE_CRASHES; |
| 705 // Find the lowest processor that our process is allows to run against | 903 PluginObject *obj = static_cast<PluginObject*>(instance->pdata); |
| 706 DWORD_PTR affinity_mask = (process_affinity_mask & | 904 StreamManager *stream_manager = obj->stream_manager(); |
| 707 ((~process_affinity_mask) + 1)); | 905 |
| 708 | 906 stream_manager->SetStreamFile(stream, fname); |
| 709 // Set this as the processor that our thread must always run against | 907 } |
| 710 // This must be a subset of the process affinity mask | 908 |
| 711 HANDLE hCurrentThread = GetCurrentThread(); | 909 int16 NPP_HandleEvent(NPP instance, void *event) { |
| 712 if (INVALID_HANDLE_VALUE != hCurrentThread) { | 910 HANDLE_CRASHES; |
| 713 SetThreadAffinityMask(hCurrentThread, affinity_mask); | 911 return 0; |
| 714 CloseHandle(hCurrentThread); | 912 } |
| 715 } | 913 } // namespace o3d |
| 914 |
| 915 namespace glue { |
| 916 namespace _o3d { |
| 917 bool PluginObject::GetDisplayMode(int mode_id, o3d::DisplayMode *mode) { |
| 918 return renderer()->GetDisplayMode(mode_id, mode); |
| 919 } |
| 920 |
| 921 // TODO: Where should this really live? It's platform-specific, but in |
| 922 // PluginObject, which mainly lives in cross/o3d_glue.h+cc. |
| 923 bool PluginObject::RequestFullscreenDisplay() { |
| 924 bool success = false; |
| 925 DCHECK(GetPluginHWnd()); |
| 926 if (!fullscreen_ && renderer_ && fullscreen_region_valid_) { |
| 927 DCHECK(renderer_->fullscreen() == fullscreen_); |
| 928 DCHECK(!GetFullscreenHWnd()); |
| 929 HWND drawing_hwnd = |
| 930 CreateFullscreenWindow(this, fullscreen_region_mode_id_); |
| 931 if (drawing_hwnd) { |
| 932 ::KillTimer(GetHWnd(), 0); |
| 933 SetFullscreenHWnd(drawing_hwnd); |
| 934 StorePluginPropertyUnsafe(drawing_hwnd, this); |
| 935 |
| 936 DisplayWindowWindows display; |
| 937 display.set_hwnd(GetHWnd()); |
| 938 if (renderer_->SetFullscreen(true, display, |
| 939 fullscreen_region_mode_id_)) { |
| 940 fullscreen_ = true; |
| 941 client()->SendResizeEvent(renderer_->width(), renderer_->height(), |
| 942 true); |
| 943 success = true; |
| 944 } else { |
| 945 CleanupFullscreenWindow(this); |
| 716 } | 946 } |
| 717 | |
| 718 CloseHandle(current_process_handle); | |
| 719 } | |
| 720 | |
| 721 return NPERR_NO_ERROR; | |
| 722 } | |
| 723 | |
| 724 NPError OSCALL NP_Initialize(NPNetscapeFuncs *browserFuncs) { | |
| 725 HANDLE_CRASHES; | |
| 726 NPError retval = InitializeNPNApi(browserFuncs); | |
| 727 if (retval != NPERR_NO_ERROR) return retval; | |
| 728 return InitializePlugin(); | |
| 729 } | |
| 730 | |
| 731 NPError OSCALL NP_Shutdown(void) { | |
| 732 HANDLE_CRASHES; | |
| 733 DLOG(INFO) << "NP_Shutdown"; | |
| 734 if (g_logger) { | |
| 735 // Do a last sweep to aggregate metrics before we shut down | |
| 736 g_logger->ProcessMetrics(true, false); | |
| 737 delete g_logger; | |
| 738 g_logger = NULL; | |
| 739 g_logging_initialized = false; | |
| 740 stats_report::g_global_metrics.Uninitialize(); | |
| 741 } | |
| 742 | |
| 743 CommandLine::Terminate(); | |
| 744 | |
| 745 // Force all base singletons to be destroyed. | |
| 746 g_at_exit_manager.reset(NULL); | |
| 747 | |
| 748 // TODO : This is commented out until we can determine if | |
| 749 // it's safe to shutdown breakpad at this stage (Gears, for | |
| 750 // example, never deletes...) | |
| 751 // Shutdown breakpad | |
| 752 // delete g_exception_manager; | |
| 753 | |
| 754 // Strictly speaking, on windows, it's not really necessary to call | |
| 755 // Stop(), but we do so for completeness | |
| 756 if (g_bluescreen_detector) { | |
| 757 g_bluescreen_detector->Stop(); | |
| 758 delete g_bluescreen_detector; | |
| 759 g_bluescreen_detector = NULL; | |
| 760 } | |
| 761 | |
| 762 return NPERR_NO_ERROR; | |
| 763 } | |
| 764 | |
| 765 NPError NPP_New(NPMIMEType pluginType, | |
| 766 NPP instance, | |
| 767 uint16 mode, | |
| 768 int16 argc, | |
| 769 char *argn[], | |
| 770 char *argv[], | |
| 771 NPSavedData *saved) { | |
| 772 HANDLE_CRASHES; | |
| 773 | |
| 774 if (!g_logging_initialized) { | |
| 775 // Get user config metrics. These won't be stored though unless the user | |
| 776 // opts-in for usagestats logging | |
| 777 GetUserAgentMetrics(instance); | |
| 778 GetUserConfigMetrics(); | |
| 779 // Create usage stats logs object | |
| 780 g_logger = o3d::PluginLogging::InitializeUsageStatsLogging(); | |
| 781 if (g_logger) { | |
| 782 // Setup blue-screen detection | |
| 783 g_bluescreen_detector = new o3d::BluescreenDetector(); | |
| 784 g_bluescreen_detector->Start(); | |
| 785 } | |
| 786 g_logging_initialized = true; | |
| 787 } | |
| 788 PluginObject* pluginObject = glue::_o3d::PluginObject::Create( | |
| 789 instance); | |
| 790 instance->pdata = pluginObject; | |
| 791 glue::_o3d::InitializeGlue(instance); | |
| 792 pluginObject->Init(argc, argn, argv); | |
| 793 return NPERR_NO_ERROR; | |
| 794 } | |
| 795 | |
| 796 void CleanupFullscreenWindow(PluginObject *obj) { | |
| 797 DCHECK(obj->GetFullscreenHWnd()); | |
| 798 obj->StorePluginProperty(obj->GetPluginHWnd(), obj); | |
| 799 ::DestroyWindow(obj->GetFullscreenHWnd()); | |
| 800 obj->SetFullscreenHWnd(NULL); | |
| 801 } | |
| 802 | |
| 803 void CleanupAllWindows(PluginObject *obj) { | |
| 804 DCHECK(obj->GetHWnd()); | |
| 805 DCHECK(obj->GetPluginHWnd()); | |
| 806 ::KillTimer(obj->GetHWnd(), 0); | |
| 807 if (obj->GetFullscreenHWnd()) { | |
| 808 CleanupFullscreenWindow(obj); | |
| 809 } | |
| 810 PluginObject::ClearPluginProperty(obj->GetHWnd()); | |
| 811 ::SetWindowLongPtr(obj->GetPluginHWnd(), | |
| 812 GWL_WNDPROC, | |
| 813 reinterpret_cast<LONG_PTR>( | |
| 814 obj->GetDefaultPluginWindowProc())); | |
| 815 obj->SetPluginHWnd(NULL); | |
| 816 obj->SetHWnd(NULL); | |
| 817 } | |
| 818 | |
| 819 NPError NPP_Destroy(NPP instance, NPSavedData **save) { | |
| 820 HANDLE_CRASHES; | |
| 821 PluginObject *obj = static_cast<PluginObject*>(instance->pdata); | |
| 822 if (obj) { | |
| 823 if (obj->GetHWnd()) { | |
| 824 CleanupAllWindows(obj); | |
| 825 } | |
| 826 | |
| 827 obj->TearDown(); | |
| 828 NPN_ReleaseObject(obj); | |
| 829 instance->pdata = NULL; | |
| 830 } | |
| 831 | |
| 832 return NPERR_NO_ERROR; | |
| 833 } | |
| 834 | |
| 835 bool PluginObject::GetDisplayMode(int mode_id, o3d::DisplayMode *mode) { | |
| 836 return renderer()->GetDisplayMode(mode_id, mode); | |
| 837 } | |
| 838 | |
| 839 | |
| 840 HWND CreateFullscreenWindow(PluginObject *obj, | |
| 841 int mode_id) { | |
| 842 o3d::DisplayMode mode; | |
| 843 if (!obj->renderer()->GetDisplayMode(mode_id, &mode)) { | |
| 844 return NULL; | |
| 845 } | |
| 846 CHECK(mode.width() > 0 && mode.height() > 0); | |
| 847 | |
| 848 HINSTANCE instance = | |
| 849 reinterpret_cast<HINSTANCE>( | |
| 850 ::GetWindowLongPtr(obj->GetPluginHWnd(), GWLP_HINSTANCE)); | |
| 851 WNDCLASSEX *wcx = obj->GetFullscreenWindowClass(instance, WindowProc); | |
| 852 HWND hWnd = CreateWindowEx(NULL, | |
| 853 wcx->lpszClassName, | |
| 854 L"O3D Test Fullscreen Window", | |
| 855 WS_POPUP, | |
| 856 0, 0, | |
| 857 mode.width(), | |
| 858 mode.height(), | |
| 859 NULL, | |
| 860 NULL, | |
| 861 instance, | |
| 862 NULL); | |
| 863 | |
| 864 ShowWindow(hWnd, SW_SHOW); | |
| 865 return hWnd; | |
| 866 } | |
| 867 | |
| 868 // TODO: Where should this really live? It's platform-specific, but in | |
| 869 // PluginObject, which mainly lives in cross/o3d_glue.h+cc. | |
| 870 bool PluginObject::RequestFullscreenDisplay() { | |
| 871 bool success = false; | |
| 872 DCHECK(GetPluginHWnd()); | |
| 873 if (!fullscreen_ && renderer_ && fullscreen_region_valid_) { | |
| 874 DCHECK(renderer_->fullscreen() == fullscreen_); | |
| 875 DCHECK(!GetFullscreenHWnd()); | |
| 876 HWND drawing_hwnd = | |
| 877 CreateFullscreenWindow(this, fullscreen_region_mode_id_); | |
| 878 if (drawing_hwnd) { | |
| 879 ::KillTimer(GetHWnd(), 0); | |
| 880 SetFullscreenHWnd(drawing_hwnd); | |
| 881 StorePluginPropertyUnsafe(drawing_hwnd, this); | |
| 882 | |
| 883 DisplayWindowWindows display; | |
| 884 display.set_hwnd(GetHWnd()); | |
| 885 if (renderer_->SetFullscreen(true, display, | |
| 886 fullscreen_region_mode_id_)) { | |
| 887 fullscreen_ = true; | |
| 888 client()->SendResizeEvent(renderer_->width(), renderer_->height(), | |
| 889 true); | |
| 890 success = true; | |
| 891 } else { | |
| 892 CleanupFullscreenWindow(this); | |
| 893 } | |
| 894 prev_width_ = renderer_->width(); | |
| 895 prev_height_ = renderer_->height(); | |
| 896 ::SetTimer(GetHWnd(), 0, 10, NULL); | |
| 897 } else { | |
| 898 LOG(ERROR) << "Failed to create fullscreen window."; | |
| 899 } | |
| 900 } | |
| 901 return success; | |
| 902 } | |
| 903 | |
| 904 void PluginObject::CancelFullscreenDisplay() { | |
| 905 DCHECK(GetPluginHWnd()); | |
| 906 if (fullscreen_) { | |
| 907 DCHECK(renderer()); | |
| 908 DCHECK(renderer()->fullscreen()); | |
| 909 ::KillTimer(GetHWnd(), 0); | |
| 910 DisplayWindowWindows display; | |
| 911 display.set_hwnd(GetPluginHWnd()); | |
| 912 if (!renderer_->SetFullscreen(false, display, 0)) { | |
| 913 LOG(FATAL) << "Failed to get the renderer out of fullscreen mode!"; | |
| 914 } | |
| 915 CleanupFullscreenWindow(this); | |
| 916 prev_width_ = renderer_->width(); | 947 prev_width_ = renderer_->width(); |
| 917 prev_height_ = renderer_->height(); | 948 prev_height_ = renderer_->height(); |
| 918 client()->SendResizeEvent(prev_width_, prev_height_, false); | |
| 919 ::SetTimer(GetHWnd(), 0, 10, NULL); | 949 ::SetTimer(GetHWnd(), 0, 10, NULL); |
| 920 fullscreen_ = false; | 950 } else { |
| 921 } | 951 LOG(ERROR) << "Failed to create fullscreen window."; |
| 922 } | 952 } |
| 923 | 953 } |
| 924 NPError NPP_SetWindow(NPP instance, NPWindow *window) { | 954 return success; |
| 925 HANDLE_CRASHES; | 955 } |
| 926 PluginObject *obj = static_cast<PluginObject*>(instance->pdata); | 956 |
| 927 | 957 void PluginObject::CancelFullscreenDisplay() { |
| 928 HWND hWnd = static_cast<HWND>(window->window); | 958 DCHECK(GetPluginHWnd()); |
| 929 if (!hWnd) { | 959 if (fullscreen_) { |
| 930 // Chrome calls us this way before NPP_Destroy. | 960 DCHECK(renderer()); |
| 931 if (obj->GetHWnd()) { | 961 DCHECK(renderer()->fullscreen()); |
| 932 CleanupAllWindows(obj); | 962 ::KillTimer(GetHWnd(), 0); |
| 933 } | 963 DisplayWindowWindows display; |
| 934 return NPERR_NO_ERROR; | 964 display.set_hwnd(GetPluginHWnd()); |
| 935 } | 965 if (!renderer_->SetFullscreen(false, display, 0)) { |
| 936 if (obj->GetHWnd() == hWnd) { | 966 LOG(FATAL) << "Failed to get the renderer out of fullscreen mode!"; |
| 937 return NPERR_NO_ERROR; | 967 } |
| 938 } | 968 CleanupFullscreenWindow(this); |
| 939 if (obj->fullscreen()) { | 969 prev_width_ = renderer_->width(); |
| 940 // We can get here if the user alt+tabs away from the fullscreen plugin | 970 prev_height_ = renderer_->height(); |
| 941 // window or JavaScript resizes the plugin window. | 971 client()->SendResizeEvent(prev_width_, prev_height_, false); |
| 942 DCHECK(obj->GetPluginHWnd()); | 972 ::SetTimer(GetHWnd(), 0, 10, NULL); |
| 943 DCHECK(obj->GetFullscreenHWnd()); | 973 fullscreen_ = false; |
| 944 DCHECK(obj->GetPluginHWnd() == hWnd); | 974 } |
| 945 return NPERR_NO_ERROR; | 975 } |
| 946 } | 976 } // namespace _o3d |
| 947 DCHECK(!obj->GetPluginHWnd()); | 977 } // namespace glue |
| 948 obj->SetPluginHWnd(hWnd); | |
| 949 obj->SetParentHWnd(::GetParent(hWnd)); | |
| 950 PluginObject::StorePluginProperty(hWnd, obj); | |
| 951 obj->SetDefaultPluginWindowProc( | |
| 952 reinterpret_cast<WNDPROC>( | |
| 953 ::SetWindowLongPtr(hWnd, | |
| 954 GWL_WNDPROC, | |
| 955 reinterpret_cast<LONG_PTR>(WindowProc)))); | |
| 956 | |
| 957 // create and assign the graphics context | |
| 958 DisplayWindowWindows default_display; | |
| 959 default_display.set_hwnd(obj->GetHWnd()); | |
| 960 | |
| 961 obj->CreateRenderer(default_display); | |
| 962 obj->client()->Init(); | |
| 963 obj->client()->SetRenderOnDemandCallback( | |
| 964 new RenderOnDemandCallbackHandler(obj)); | |
| 965 | |
| 966 // we set the timer to 10ms or 100fps. At the time of this comment | |
| 967 // the renderer does a vsync the max fps it will run will be the refresh | |
| 968 // rate of the monitor or 100fps, which ever is lower. | |
| 969 ::SetTimer(obj->GetHWnd(), 0, 10, NULL); | |
| 970 | |
| 971 return NPERR_NO_ERROR; | |
| 972 } | |
| 973 | |
| 974 // Called when the browser has finished attempting to stream data to | |
| 975 // a file as requested. If fname == NULL the attempt was not successful. | |
| 976 void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) { | |
| 977 HANDLE_CRASHES; | |
| 978 PluginObject *obj = static_cast<PluginObject*>(instance->pdata); | |
| 979 StreamManager *stream_manager = obj->stream_manager(); | |
| 980 | |
| 981 stream_manager->SetStreamFile(stream, fname); | |
| 982 } | |
| 983 | |
| 984 int16 NPP_HandleEvent(NPP instance, void *event) { | |
| 985 HANDLE_CRASHES; | |
| 986 return 0; | |
| 987 } | |
| 988 } // end extern "C" | |
| OLD | NEW |