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 <string.h> 6 7 #include "base/memory/scoped_ptr.h" 8 #include "base/memory/weak_ptr.h" 9 #include "content/browser/gamepad/gamepad_test_helpers.h" 10 #include "content/browser/renderer_host/pepper/browser_ppapi_host_test.h" 11 #include "content/browser/renderer_host/pepper/pepper_gamepad_host.h" 12 #include "content/common/gamepad_hardware_buffer.h" 13 #include "ppapi/c/pp_errors.h" 14 #include "ppapi/host/host_message_context.h" 15 #include "ppapi/proxy/gamepad_resource.h" 16 #include "ppapi/proxy/ppapi_messages.h" 17 #include "ppapi/proxy/resource_message_params.h" 18 #include "ppapi/shared_impl/ppb_gamepad_shared.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 namespace content { 22 23 namespace { 24 25 class PepperGamepadHostTest 26 : public testing::Test, 27 public BrowserPpapiHostTest { 28 public: 29 PepperGamepadHostTest() { 30 } 31 virtual ~PepperGamepadHostTest() { 32 } 33 34 void ConstructService(const WebKit::WebGamepads& test_data) { 35 service_.reset(new GamepadServiceTestConstructor(test_data)); 36 } 37 38 GamepadService* gamepad_service() { return service_->gamepad_service(); } 39 40 protected: 41 scoped_ptr<GamepadServiceTestConstructor> service_; 42 43 DISALLOW_COPY_AND_ASSIGN(PepperGamepadHostTest); 44 }; 45 46 inline ptrdiff_t AddressDiff(const void* a, const void* b) { 47 return static_cast<const char*>(a) - static_cast<const char*>(b); 48 } 49 50 } // namespace 51 52 // Validate the memory layout of the Pepper proxy struct matches the content 53 // one. The proxy can't depend on content so has a duplicate definition. This 54 // code can see both definitions so we do the validation here. 55 TEST_F(PepperGamepadHostTest, ValidateHardwareBuffersMatch) { 56 // Hardware buffer. 57 COMPILE_ASSERT(sizeof(ppapi::ContentGamepadHardwareBuffer) == 58 sizeof(GamepadHardwareBuffer), 59 gamepad_hardware_buffers_must_match); 60 ppapi::ContentGamepadHardwareBuffer ppapi_buf; 61 GamepadHardwareBuffer content_buf; 62 EXPECT_EQ(AddressDiff(&content_buf.sequence, &content_buf), 63 AddressDiff(&ppapi_buf.sequence, &ppapi_buf)); 64 EXPECT_EQ(AddressDiff(&content_buf.buffer, &content_buf), 65 AddressDiff(&ppapi_buf.buffer, &ppapi_buf)); 66 } 67 68 TEST_F(PepperGamepadHostTest, ValidateGamepadsMatch) { 69 // Gamepads. 70 COMPILE_ASSERT(sizeof(ppapi::WebKitGamepads) == 71 sizeof(WebKit::WebGamepads), 72 gamepads_data_must_match); 73 ppapi::WebKitGamepads ppapi_gamepads; 74 WebKit::WebGamepads web_gamepads; 75 EXPECT_EQ(AddressDiff(&web_gamepads.length, &web_gamepads), 76 AddressDiff(&ppapi_gamepads.length, &ppapi_gamepads)); 77 78 // See comment below on storage & the EXPECT macro. 79 size_t webkit_items_length_cap = WebKit::WebGamepads::itemsLengthCap; 80 size_t ppapi_items_length_cap = ppapi::WebKitGamepads::kItemsLengthCap; 81 EXPECT_EQ(webkit_items_length_cap, ppapi_items_length_cap); 82 83 for (size_t i = 0; i < web_gamepads.itemsLengthCap; i++) { 84 EXPECT_EQ(AddressDiff(&web_gamepads.items[0], &web_gamepads), 85 AddressDiff(&ppapi_gamepads.items[0], &ppapi_gamepads)); 86 } 87 } 88 89 TEST_F(PepperGamepadHostTest, ValidateGamepadMatch) { 90 // Gamepad. 91 COMPILE_ASSERT(sizeof(ppapi::WebKitGamepad) == 92 sizeof(WebKit::WebGamepad), 93 gamepad_data_must_match); 94 ppapi::WebKitGamepad ppapi_gamepad; 95 WebKit::WebGamepad web_gamepad; 96 97 // Using EXPECT seems to force storage for the parameter, which the constants 98 // in the WebKit/PPAPI headers don't have. So we have to use temporaries 99 // before comparing them. 100 size_t webkit_id_length_cap = WebKit::WebGamepad::idLengthCap; 101 size_t ppapi_id_length_cap = ppapi::WebKitGamepad::kIdLengthCap; 102 EXPECT_EQ(webkit_id_length_cap, ppapi_id_length_cap); 103 104 size_t webkit_axes_length_cap = WebKit::WebGamepad::axesLengthCap; 105 size_t ppapi_axes_length_cap = ppapi::WebKitGamepad::kAxesLengthCap; 106 EXPECT_EQ(webkit_axes_length_cap, ppapi_axes_length_cap); 107 108 size_t webkit_buttons_length_cap = WebKit::WebGamepad::buttonsLengthCap; 109 size_t ppapi_buttons_length_cap = ppapi::WebKitGamepad::kButtonsLengthCap; 110 EXPECT_EQ(webkit_buttons_length_cap, ppapi_buttons_length_cap); 111 112 EXPECT_EQ(AddressDiff(&web_gamepad.connected, &web_gamepad), 113 AddressDiff(&ppapi_gamepad.connected, &ppapi_gamepad)); 114 EXPECT_EQ(AddressDiff(&web_gamepad.id, &web_gamepad), 115 AddressDiff(&ppapi_gamepad.id, &ppapi_gamepad)); 116 EXPECT_EQ(AddressDiff(&web_gamepad.timestamp, &web_gamepad), 117 AddressDiff(&ppapi_gamepad.timestamp, &ppapi_gamepad)); 118 EXPECT_EQ(AddressDiff(&web_gamepad.axesLength, &web_gamepad), 119 AddressDiff(&ppapi_gamepad.axes_length, &ppapi_gamepad)); 120 EXPECT_EQ(AddressDiff(&web_gamepad.axes, &web_gamepad), 121 AddressDiff(&ppapi_gamepad.axes, &ppapi_gamepad)); 122 EXPECT_EQ(AddressDiff(&web_gamepad.buttonsLength, &web_gamepad), 123 AddressDiff(&ppapi_gamepad.buttons_length, &ppapi_gamepad)); 124 EXPECT_EQ(AddressDiff(&web_gamepad.buttons, &web_gamepad), 125 AddressDiff(&ppapi_gamepad.buttons, &ppapi_gamepad)); 126 } 127 128 TEST_F(PepperGamepadHostTest, WaitForReply) { 129 WebKit::WebGamepads default_data; 130 memset(&default_data, 0, sizeof(WebKit::WebGamepads)); 131 default_data.length = 1; 132 default_data.items[0].connected = true; 133 default_data.items[0].buttonsLength = 1; 134 ConstructService(default_data); 135 136 PP_Instance pp_instance = 12345; 137 PP_Resource pp_resource = 67890; 138 PepperGamepadHost gamepad_host(gamepad_service(), GetBrowserPpapiHost(), 139 pp_instance, pp_resource); 140 141 // Synthesize a request for gamepad data. 142 ppapi::host::HostMessageContext context( 143 ppapi::proxy::ResourceMessageCallParams(pp_resource, 1)); 144 EXPECT_EQ(PP_OK_COMPLETIONPENDING, 145 gamepad_host.OnResourceMessageReceived( 146 PpapiHostMsg_Gamepad_RequestMemory(), 147 &context)); 148 149 // Wait for the gamepad background thread to read twice to make sure we 150 // don't get a message yet (see below for why). 151 MockGamepadDataFetcher* fetcher = service_->data_fetcher(); 152 fetcher->WaitForDataRead(); 153 fetcher->WaitForDataRead(); 154 155 // It should not have sent the callback message. 156 service_->message_loop().RunUntilIdle(); 157 EXPECT_EQ(0u, sink().message_count()); 158 159 // Set a button down and wait for it to be read twice. 160 // 161 // We wait for two reads before calling RunAllPending because the provider 162 // will read the data on the background thread (setting the event) and *then* 163 // will issue the callback on our thread. Waiting for it to read twice 164 // ensures that it was able to issue callbacks for the first read (if it 165 // issued one) before we try to check for it. 166 WebKit::WebGamepads button_down_data = default_data; 167 button_down_data.items[0].buttons[0] = 1.f; 168 fetcher->SetTestData(button_down_data); 169 fetcher->WaitForDataRead(); 170 fetcher->WaitForDataRead(); 171 172 // It should have sent a callback. 173 service_->message_loop().RunUntilIdle(); 174 ppapi::proxy::ResourceMessageReplyParams reply_params; 175 IPC::Message reply_msg; 176 ASSERT_TRUE(sink().GetFirstResourceReplyMatching( 177 PpapiPluginMsg_Gamepad_SendMemory::ID, &reply_params, &reply_msg)); 178 179 // Extract the shared memory handle. 180 base::SharedMemoryHandle reply_handle; 181 EXPECT_TRUE(reply_params.TakeSharedMemoryHandleAtIndex(0, &reply_handle)); 182 183 // Validate the shared memory. 184 base::SharedMemory shared_memory(reply_handle, true); 185 EXPECT_TRUE(shared_memory.Map(sizeof(ppapi::ContentGamepadHardwareBuffer))); 186 const ppapi::ContentGamepadHardwareBuffer* buffer = 187 static_cast<const ppapi::ContentGamepadHardwareBuffer*>( 188 shared_memory.memory()); 189 EXPECT_EQ(button_down_data.length, buffer->buffer.length); 190 EXPECT_EQ(button_down_data.items[0].buttonsLength, 191 buffer->buffer.items[0].buttons_length); 192 for (size_t i = 0; i < ppapi::WebKitGamepad::kButtonsLengthCap; i++) { 193 EXPECT_EQ(button_down_data.items[0].buttons[i], 194 buffer->buffer.items[0].buttons[i]); 195 } 196 197 // Duplicate requests should be denied. 198 EXPECT_EQ(PP_ERROR_FAILED, 199 gamepad_host.OnResourceMessageReceived( 200 PpapiHostMsg_Gamepad_RequestMemory(), 201 &context)); 202 } 203 204 } // namespace content 205