1 // Copyright (c) 2012 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 "ppapi/proxy/flash_menu_resource.h" 6 7 #include "ppapi/c/pp_errors.h" 8 #include "ppapi/proxy/ppapi_messages.h" 9 #include "ppapi/proxy/serialized_flash_menu.h" 10 11 namespace ppapi { 12 namespace proxy { 13 14 FlashMenuResource::FlashMenuResource(Connection connection, 15 PP_Instance instance) 16 : PluginResource(connection, instance), 17 selected_id_dest_(NULL) { 18 } 19 20 FlashMenuResource::~FlashMenuResource() { 21 } 22 23 bool FlashMenuResource::Initialize(const PP_Flash_Menu* menu_data) { 24 SerializedFlashMenu serialized_menu; 25 if (!menu_data || !serialized_menu.SetPPMenu(menu_data)) 26 return false; 27 SendCreate(RENDERER, PpapiHostMsg_FlashMenu_Create(serialized_menu)); 28 return true; 29 } 30 31 thunk::PPB_Flash_Menu_API* FlashMenuResource::AsPPB_Flash_Menu_API() { 32 return this; 33 } 34 35 int32_t FlashMenuResource::Show( 36 const PP_Point* location, 37 int32_t* selected_id, 38 scoped_refptr<TrackedCallback> callback) { 39 if (TrackedCallback::IsPending(callback_)) 40 return PP_ERROR_INPROGRESS; 41 42 selected_id_dest_ = selected_id; 43 callback_ = callback; 44 45 // This must be a sync message even though we don't care about the result. 46 // The actual reply will be sent asynchronously in the future. This sync 47 // request is due to the following deadlock: 48 // 49 // 1. Flash sends a show request to the renderer. 50 // 2. The show handler in the renderer (in the case of full screen) requests 51 // the window rect which is a sync message to the browser. This causes 52 // a nested message loop to be spun up in the renderer. 53 // 3. Flash expects context menus to be synchronous so it starts a nested 54 // message loop. This creates a second nested message loop in both the 55 // plugin and renderer process. 56 // 4. The browser sends the window rect reply to unblock the renderer, but 57 // it's in the second nested message loop and the reply will *not* 58 // unblock this loop. 59 // 5. The second loop won't exit until the message loop is complete, but 60 // that can't start until the first one exits. 61 // 62 // Having this message sync forces the sync request from the renderer to the 63 // browser for the window rect will complete before Flash can run a nested 64 // message loop to wait for the result of the menu. 65 SyncCall<IPC::Message>(RENDERER, PpapiHostMsg_FlashMenu_Show(*location)); 66 return PP_OK_COMPLETIONPENDING; 67 } 68 69 void FlashMenuResource::OnReplyReceived( 70 const proxy::ResourceMessageReplyParams& params, 71 const IPC::Message& msg) { 72 // Because the Show call is synchronous but we ignore the sync result, we 73 // can't use the normal reply dispatch and have to do it manually here. 74 switch (msg.type()) { 75 case PpapiPluginMsg_FlashMenu_ShowReply::ID: { 76 int32_t selected_id; 77 if (ppapi::UnpackMessage<PpapiPluginMsg_FlashMenu_ShowReply>( 78 msg, &selected_id)) 79 OnShowReply(params, selected_id); 80 break; 81 } 82 } 83 } 84 85 void FlashMenuResource::OnShowReply( 86 const proxy::ResourceMessageReplyParams& params, 87 int32_t selected_id) { 88 if (!TrackedCallback::IsPending(callback_)) 89 return; 90 91 *selected_id_dest_ = selected_id; 92 selected_id_dest_ = NULL; 93 callback_->Run(params.result()); 94 } 95 96 } // namespace proxy 97 } // namespace ppapi 98