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
FlashMenuResource(Connection connection,PP_Instance instance)14 FlashMenuResource::FlashMenuResource(Connection connection,
15 PP_Instance instance)
16 : PluginResource(connection, instance),
17 selected_id_dest_(NULL) {
18 }
19
~FlashMenuResource()20 FlashMenuResource::~FlashMenuResource() {
21 }
22
Initialize(const PP_Flash_Menu * menu_data)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
AsPPB_Flash_Menu_API()31 thunk::PPB_Flash_Menu_API* FlashMenuResource::AsPPB_Flash_Menu_API() {
32 return this;
33 }
34
Show(const PP_Point * location,int32_t * selected_id,scoped_refptr<TrackedCallback> callback)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
OnReplyReceived(const proxy::ResourceMessageReplyParams & params,const IPC::Message & msg)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
OnShowReply(const proxy::ResourceMessageReplyParams & params,int32_t selected_id)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