OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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 <map> | |
6 #include <vector> | |
7 | |
8 #include "base/string_util.h" | |
9 #include "base/utf_string_conversions.h" | |
10 #include "build/build_config.h" | |
11 #include "chrome/common/render_messages.h" | |
12 #include "chrome/renderer/pepper_devices.h" | |
13 #include "chrome/renderer/webplugin_delegate_pepper.h" | |
14 #include "chrome/test/render_view_test.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 #include "third_party/npapi/bindings/npapi.h" | |
17 #include "third_party/npapi/bindings/npruntime.h" | |
18 #include "third_party/WebKit/WebKit/chromium/public/WebPlugin.h" | |
19 #include "third_party/WebKit/WebKit/chromium/public/WebPluginParams.h" | |
20 #include "third_party/WebKit/WebKit/chromium/public/WebRect.h" | |
21 #include "webkit/glue/plugins/plugin_instance.h" | |
22 #include "webkit/glue/plugins/plugin_list.h" | |
23 #include "webkit/glue/plugins/webplugin_impl.h" | |
24 | |
25 class PepperDeviceTest; | |
26 | |
27 namespace { | |
28 | |
29 const char kTestPluginMimeType[] = "chrome-test/pepper-device-test"; | |
30 | |
31 // This maps the NPP instances to the test object so our C callbacks can easily | |
32 // get back to the object. There will normally be only one item in this map. | |
33 static std::map<NPP, PepperDeviceTest*> active_tests; | |
34 | |
35 NPError NPP_New(NPMIMEType plugin_type, NPP instance, | |
36 uint16 mode, int16 argc, char* argn[], | |
37 char* argv[], NPSavedData* saved) { | |
38 // Watch out: active_tests won't contain the NPP pointer until after this | |
39 // call is complete, so don't use it. | |
40 return NPERR_NO_ERROR; | |
41 } | |
42 | |
43 NPError NPP_Destroy(NPP instance, NPSavedData** saved) { | |
44 if (!instance) | |
45 return NPERR_INVALID_INSTANCE_ERROR; | |
46 return NPERR_NO_ERROR; | |
47 } | |
48 | |
49 NPError NPP_SetWindow(NPP instance, NPWindow* window) { | |
50 return NPERR_NO_ERROR; | |
51 } | |
52 | |
53 int16 NPP_HandleEvent(NPP instance, void* event) { | |
54 return 0; | |
55 } | |
56 | |
57 NPError NPP_GetValue(NPP instance, NPPVariable variable, void* value) { | |
58 if (!instance) | |
59 return NPERR_INVALID_INSTANCE_ERROR; | |
60 switch (variable) { | |
61 case NPPVpluginNeedsXEmbed: | |
62 *static_cast<NPBool*>(value) = 1; | |
63 return NPERR_NO_ERROR; | |
64 default: | |
65 return NPERR_INVALID_PARAM; | |
66 } | |
67 } | |
68 | |
69 NPError NPP_SetValue(NPP instance, NPNVariable variable, void* value) { | |
70 return NPERR_NO_ERROR; | |
71 } | |
72 | |
73 NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* plugin_funcs) { | |
74 plugin_funcs->newp = NPP_New; | |
75 plugin_funcs->destroy = NPP_Destroy; | |
76 plugin_funcs->setwindow = NPP_SetWindow; | |
77 plugin_funcs->event = NPP_HandleEvent; | |
78 plugin_funcs->getvalue = NPP_GetValue; | |
79 plugin_funcs->setvalue = NPP_SetValue; | |
80 return NPERR_NO_ERROR; | |
81 } | |
82 | |
83 #if defined(OS_MACOSX) || defined(OS_WIN) | |
84 NPError API_CALL NP_Initialize(NPNetscapeFuncs* browser_funcs) { | |
85 return NPERR_NO_ERROR; | |
86 } | |
87 #else | |
88 NPError API_CALL NP_Initialize(NPNetscapeFuncs* browser_funcs, | |
89 NPPluginFuncs* plugin_funcs) { | |
90 NP_GetEntryPoints(plugin_funcs); | |
91 return NPERR_NO_ERROR; | |
92 } | |
93 #endif | |
94 | |
95 NPError API_CALL NP_Shutdown() { | |
96 return NPERR_NO_ERROR; | |
97 } | |
98 | |
99 } // namespace | |
100 | |
101 // PepperDeviceTest ------------------------------------------------------------ | |
102 | |
103 class PepperDeviceTest : public RenderViewTest { | |
104 public: | |
105 PepperDeviceTest(); | |
106 ~PepperDeviceTest(); | |
107 | |
108 const FilePath& plugin_path() const { return version_info_.path; } | |
109 | |
110 WebPluginDelegatePepper* pepper_plugin() const { return pepper_plugin_; } | |
111 | |
112 NPP npp() const { return pepper_plugin_->instance()->npp(); } | |
113 | |
114 protected: | |
115 // Logs that the given flush command was called in flush_calls. | |
116 static void FlushCalled(NPP instance, | |
117 NPDeviceContext* context, | |
118 NPError err, | |
119 NPUserData* user_data); | |
120 | |
121 // Audio callback, currently empty. | |
122 static void AudioCallback(NPDeviceContextAudio* context); | |
123 | |
124 // A log of flush commands we can use to check the async callbacks. | |
125 struct FlushData { | |
126 NPP instance; | |
127 NPDeviceContext* context; | |
128 NPError err; | |
129 NPUserData* user_data; | |
130 }; | |
131 std::vector<FlushData> flush_calls_; | |
132 | |
133 private: | |
134 // testing::Test implementation. | |
135 virtual void SetUp(); | |
136 virtual void TearDown(); | |
137 | |
138 NPAPI::PluginVersionInfo version_info_; | |
139 | |
140 scoped_ptr<webkit_glue::WebPluginImpl> plugin_; | |
141 WebPluginDelegatePepper* pepper_plugin_; // FIXME(brettw): check lifetime. | |
142 }; | |
143 | |
144 PepperDeviceTest::PepperDeviceTest() { | |
145 version_info_.path = FilePath(FILE_PATH_LITERAL("pepper-device-tester")); | |
146 version_info_.product_name = ASCIIToWide("Pepper device test plugin"); | |
147 version_info_.file_description = ASCIIToWide("Pepper device test plugin"); | |
148 version_info_.file_version = ASCIIToWide("1"); | |
149 version_info_.mime_types = ASCIIToWide(kTestPluginMimeType); | |
150 NPAPI::PluginEntryPoints entry_points = { | |
151 #if !defined(OS_POSIX) || defined(OS_MACOSX) | |
152 NP_GetEntryPoints, | |
153 #endif | |
154 NP_Initialize, | |
155 NP_Shutdown | |
156 }; | |
157 version_info_.entry_points = entry_points; | |
158 } | |
159 | |
160 PepperDeviceTest::~PepperDeviceTest() { | |
161 } | |
162 | |
163 void PepperDeviceTest::SetUp() { | |
164 RenderViewTest::SetUp(); | |
165 | |
166 NPAPI::PluginList::Singleton()->RegisterInternalPlugin(version_info_); | |
167 | |
168 // Create the WebKit plugin with no delegates (this seems to work | |
169 // sufficiently for the test). | |
170 WebKit::WebPluginParams params; | |
171 plugin_.reset(new webkit_glue::WebPluginImpl( | |
172 NULL, params, FilePath(), std::string(), | |
173 base::WeakPtr<webkit_glue::WebPluginPageDelegate>())); | |
174 | |
175 // Create a pepper plugin for the RenderView. | |
176 pepper_plugin_ = WebPluginDelegatePepper::Create( | |
177 plugin_path(), kTestPluginMimeType, view_->AsWeakPtr()); | |
178 ASSERT_TRUE(pepper_plugin_); | |
179 ASSERT_TRUE(pepper_plugin_->Initialize(GURL(), std::vector<std::string>(), | |
180 std::vector<std::string>(), | |
181 plugin_.get(), false)); | |
182 | |
183 // Normally the RenderView creates the pepper plugin and registers it with | |
184 // its internal list. Since we're creating it manually, we have to reach in | |
185 // and register it to prevent tear-down from asserting. | |
186 view_->current_oldstyle_pepper_plugins_.insert(pepper_plugin_); | |
187 | |
188 active_tests[npp()] = this; | |
189 | |
190 // Need to specify a window size or graphics calls will fail on the 0x0 | |
191 // bitmap. | |
192 gfx::Rect rect(0, 0, 100, 100); | |
193 view_->OnResize(rect.size(), gfx::Rect()); | |
194 pepper_plugin_->UpdateGeometry(rect, rect); | |
195 } | |
196 | |
197 void PepperDeviceTest::TearDown() { | |
198 active_tests.erase(active_tests.find(npp())); | |
199 | |
200 plugin_.reset(); | |
201 if (pepper_plugin_) | |
202 pepper_plugin_->PluginDestroyed(); | |
203 | |
204 NPAPI::PluginList::Singleton()->UnregisterInternalPlugin(version_info_.path); | |
205 | |
206 RenderViewTest::TearDown(); | |
207 } | |
208 | |
209 // static | |
210 void PepperDeviceTest::FlushCalled(NPP instance, | |
211 NPDeviceContext* context, | |
212 NPError err, | |
213 NPUserData* user_data) { | |
214 if (active_tests.find(instance) == active_tests.end()) | |
215 return; | |
216 PepperDeviceTest* that = active_tests[instance]; | |
217 | |
218 FlushData flush_data; | |
219 flush_data.instance = instance; | |
220 flush_data.context = context; | |
221 flush_data.err = err; | |
222 flush_data.user_data = user_data; | |
223 that->flush_calls_.push_back(flush_data); | |
224 } | |
225 | |
226 void PepperDeviceTest::AudioCallback(NPDeviceContextAudio* context) { | |
227 } | |
228 | |
229 | |
230 // ----------------------------------------------------------------------------- | |
231 | |
232 // TODO(brettw) this crashes on Mac. Figure out why and enable. | |
233 #if !defined(OS_MACOSX) | |
234 | |
235 TEST_F(PepperDeviceTest, Flush) { | |
236 // Create a 2D device. | |
237 NPDeviceContext2DConfig config; | |
238 NPDeviceContext2D context; | |
239 EXPECT_EQ(NPERR_NO_ERROR, | |
240 pepper_plugin()->Device2DInitializeContext(&config, &context)); | |
241 | |
242 // Flush the bitmap. Here we fake the invalidate call to the RenderView since | |
243 // there isn't an actual visible web page that would otherwise get painted. | |
244 // The callback should not get called synchronously. | |
245 pepper_plugin()->Device2DFlushContext(npp(), &context, &FlushCalled, NULL); | |
246 view_->didInvalidateRect(WebKit::WebRect(0, 0, 100, 100)); | |
247 EXPECT_TRUE(flush_calls_.empty()); | |
248 | |
249 // Run the message loop which should process the pending paints, there should | |
250 // still be no callbacks since the stuff hasn't been copied to the screen, | |
251 // but there should be a paint message sent to the browser. | |
252 MessageLoop::current()->RunAllPending(); | |
253 EXPECT_TRUE(flush_calls_.empty()); | |
254 EXPECT_TRUE(render_thread_.sink().GetFirstMessageMatching( | |
255 ViewHostMsg_UpdateRect::ID)); | |
256 | |
257 // Send a paint ACK, this should trigger the callback. | |
258 view_->OnMessageReceived(ViewMsg_UpdateRect_ACK(view_->routing_id())); | |
259 EXPECT_EQ(1u, flush_calls_.size()); | |
260 } | |
261 #endif | |
262 | |
263 TEST_F(PepperDeviceTest, AudioInit) { | |
264 NPDeviceContextAudioConfig config; | |
265 config.sampleRate = NPAudioSampleRate44100Hz; | |
266 config.sampleType = NPAudioSampleTypeInt16; | |
267 config.outputChannelMap = NPAudioChannelStereo; | |
268 config.callback = &AudioCallback; | |
269 config.userData = this; | |
270 NPDeviceContextAudio context; | |
271 EXPECT_EQ(NPERR_NO_ERROR, | |
272 pepper_plugin()->DeviceAudioInitializeContext(&config, &context)); | |
273 EXPECT_TRUE(render_thread_.sink().GetFirstMessageMatching( | |
274 ViewHostMsg_CreateAudioStream::ID)); | |
275 EXPECT_EQ(NPERR_NO_ERROR, | |
276 pepper_plugin()->DeviceAudioDestroyContext(&context)); | |
277 EXPECT_TRUE(render_thread_.sink().GetFirstMessageMatching( | |
278 ViewHostMsg_CloseAudioStream::ID)); | |
279 } | |
280 | |
OLD | NEW |