OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/render_widget_fullscreen_pepper.h" | 5 #include "chrome/renderer/render_widget_fullscreen_pepper.h" |
6 | 6 |
7 #include "chrome/common/render_messages.h" | 7 #include "chrome/common/render_messages.h" |
8 #include "chrome/renderer/ggl/ggl.h" | |
9 #include "chrome/renderer/gpu_channel_host.h" | |
10 #include "chrome/renderer/pepper_platform_context_3d_impl.h" | |
8 #include "chrome/renderer/render_thread.h" | 11 #include "chrome/renderer/render_thread.h" |
12 #include "gpu/command_buffer/client/gles2_implementation.h" | |
9 #include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h" | 13 #include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h" |
10 #include "third_party/WebKit/WebKit/chromium/public/WebSize.h" | 14 #include "third_party/WebKit/WebKit/chromium/public/WebSize.h" |
11 #include "third_party/WebKit/WebKit/chromium/public/WebWidget.h" | 15 #include "third_party/WebKit/WebKit/chromium/public/WebWidget.h" |
12 #include "webkit/plugins/ppapi/fullscreen_container.h" | 16 #include "webkit/plugins/ppapi/plugin_delegate.h" |
13 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" | 17 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" |
14 | 18 |
15 using WebKit::WebCanvas; | 19 using WebKit::WebCanvas; |
16 using WebKit::WebCompositionUnderline; | 20 using WebKit::WebCompositionUnderline; |
17 using WebKit::WebCursorInfo; | 21 using WebKit::WebCursorInfo; |
18 using WebKit::WebInputEvent; | 22 using WebKit::WebInputEvent; |
19 using WebKit::WebRect; | 23 using WebKit::WebRect; |
20 using WebKit::WebSize; | 24 using WebKit::WebSize; |
21 using WebKit::WebString; | 25 using WebKit::WebString; |
22 using WebKit::WebTextDirection; | 26 using WebKit::WebTextDirection; |
(...skipping 18 matching lines...) Expand all Loading... | |
41 delete this; | 45 delete this; |
42 } | 46 } |
43 | 47 |
44 virtual WebSize size() { | 48 virtual WebSize size() { |
45 return size_; | 49 return size_; |
46 } | 50 } |
47 | 51 |
48 virtual void resize(const WebSize& size) { | 52 virtual void resize(const WebSize& size) { |
49 size_ = size; | 53 size_ = size; |
50 WebRect plugin_rect(0, 0, size_.width, size_.height); | 54 WebRect plugin_rect(0, 0, size_.width, size_.height); |
51 // TODO(piman): transparently scale the plugin instead of resizing it. | |
52 plugin_->ViewChanged(plugin_rect, plugin_rect); | 55 plugin_->ViewChanged(plugin_rect, plugin_rect); |
53 widget_->GenerateFullRepaint(); | 56 widget_->Invalidate(); |
54 } | 57 } |
55 | 58 |
56 virtual void layout() { | 59 virtual void layout() { |
57 } | 60 } |
58 | 61 |
59 virtual void paint(WebCanvas* canvas, const WebRect& rect) { | 62 virtual void paint(WebCanvas* canvas, const WebRect& rect) { |
60 if (!plugin_) | 63 if (!plugin_) |
61 return; | 64 return; |
62 WebRect plugin_rect(0, 0, size_.width, size_.height); | 65 WebRect plugin_rect(0, 0, size_.width, size_.height); |
63 plugin_->Paint(canvas, plugin_rect, rect); | 66 plugin_->Paint(canvas, plugin_rect, rect); |
64 } | 67 } |
65 | 68 |
66 virtual void composite(bool finish) { | 69 virtual void composite(bool finish) { |
67 NOTIMPLEMENTED(); | 70 ggl::Context* context = widget_->context(); |
71 DCHECK(context); | |
72 gpu::gles2::GLES2Implementation* gl = ggl::GetImplementation(context); | |
73 unsigned int texture = plugin_->GetBackingTextureId(); | |
74 gl->BindTexture(GL_TEXTURE_2D, texture); | |
75 gl->DrawArrays(GL_TRIANGLES, 0, 3); | |
76 ggl::SwapBuffers(context); | |
68 } | 77 } |
69 | 78 |
70 virtual void themeChanged() { | 79 virtual void themeChanged() { |
71 NOTIMPLEMENTED(); | 80 NOTIMPLEMENTED(); |
72 } | 81 } |
73 | 82 |
74 virtual bool handleInputEvent(const WebInputEvent& event) { | 83 virtual bool handleInputEvent(const WebInputEvent& event) { |
75 if (!plugin_) | 84 if (!plugin_) |
76 return false; | 85 return false; |
77 return plugin_->HandleInputEvent(event, &cursor_); | 86 return plugin_->HandleInputEvent(event, &cursor_); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
112 virtual WebRect caretOrSelectionBounds() { | 121 virtual WebRect caretOrSelectionBounds() { |
113 NOTIMPLEMENTED(); | 122 NOTIMPLEMENTED(); |
114 return WebRect(); | 123 return WebRect(); |
115 } | 124 } |
116 | 125 |
117 virtual void setTextDirection(WebTextDirection) { | 126 virtual void setTextDirection(WebTextDirection) { |
118 NOTIMPLEMENTED(); | 127 NOTIMPLEMENTED(); |
119 } | 128 } |
120 | 129 |
121 virtual bool isAcceleratedCompositingActive() const { | 130 virtual bool isAcceleratedCompositingActive() const { |
122 // TODO(piman): see if supporting accelerated compositing makes sense. | 131 return widget_->context() && plugin_ && |
123 return false; | 132 (plugin_->GetBackingTextureId() != 0); |
124 } | 133 } |
125 | 134 |
126 private: | 135 private: |
127 webkit::ppapi::PluginInstance* plugin_; | 136 webkit::ppapi::PluginInstance* plugin_; |
128 RenderWidgetFullscreenPepper* widget_; | 137 RenderWidgetFullscreenPepper* widget_; |
129 WebSize size_; | 138 WebSize size_; |
130 WebCursorInfo cursor_; | 139 WebCursorInfo cursor_; |
131 | 140 |
132 DISALLOW_COPY_AND_ASSIGN(PepperWidget); | 141 DISALLOW_COPY_AND_ASSIGN(PepperWidget); |
133 }; | 142 }; |
134 | 143 |
135 | |
136 // A FullscreenContainer that forwards the API calls to the | |
137 // RenderWidgetFullscreenPepper. | |
138 class WidgetFullscreenContainer | |
139 : public webkit::ppapi::FullscreenContainer { | |
140 public: | |
141 explicit WidgetFullscreenContainer(RenderWidgetFullscreenPepper* widget) | |
142 : widget_(widget) { | |
143 } | |
144 virtual ~WidgetFullscreenContainer() { } | |
145 | |
146 virtual void Invalidate() { | |
147 widget_->GenerateFullRepaint(); | |
148 } | |
149 | |
150 virtual void InvalidateRect(const WebKit::WebRect& rect) { | |
151 widget_->didInvalidateRect(rect); | |
152 } | |
153 | |
154 virtual void ScrollRect(int dx, int dy, const WebKit::WebRect& rect) { | |
155 widget_->didScrollRect(dx, dy, rect); | |
156 } | |
157 | |
158 virtual void Destroy() { | |
159 widget_->SendClose(); | |
160 } | |
161 | |
162 private: | |
163 RenderWidgetFullscreenPepper* widget_; | |
164 | |
165 DISALLOW_COPY_AND_ASSIGN(WidgetFullscreenContainer); | |
166 }; | |
167 | |
168 } // anonymous namespace | 144 } // anonymous namespace |
169 | 145 |
170 // static | 146 // static |
171 RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create( | 147 RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create( |
172 int32 opener_id, RenderThreadBase* render_thread, | 148 int32 opener_id, RenderThreadBase* render_thread, |
173 webkit::ppapi::PluginInstance* plugin) { | 149 webkit::ppapi::PluginInstance* plugin) { |
174 DCHECK_NE(MSG_ROUTING_NONE, opener_id); | 150 DCHECK_NE(MSG_ROUTING_NONE, opener_id); |
175 scoped_refptr<RenderWidgetFullscreenPepper> widget( | 151 scoped_refptr<RenderWidgetFullscreenPepper> widget( |
176 new RenderWidgetFullscreenPepper(render_thread, plugin)); | 152 new RenderWidgetFullscreenPepper(render_thread, plugin)); |
177 widget->Init(opener_id); | 153 widget->Init(opener_id); |
178 return widget.release(); | 154 return widget.release(); |
179 } | 155 } |
180 | 156 |
181 RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper( | 157 RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper( |
182 RenderThreadBase* render_thread, | 158 RenderThreadBase* render_thread, |
183 webkit::ppapi::PluginInstance* plugin) | 159 webkit::ppapi::PluginInstance* plugin) |
184 : RenderWidgetFullscreen(render_thread, WebKit::WebPopupTypeSelect), | 160 : RenderWidgetFullscreen(render_thread, WebKit::WebPopupTypeSelect), |
185 plugin_(plugin), | 161 plugin_(plugin), |
186 ALLOW_THIS_IN_INITIALIZER_LIST( | 162 #if defined(OS_MACOSX) |
187 container_(new WidgetFullscreenContainer(this))) { | 163 plugin_handle_(NULL), |
164 #endif | |
165 context_(NULL) { | |
188 } | 166 } |
189 | 167 |
190 RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() { | 168 RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() { |
169 if (context_) { | |
170 ggl::DestroyContext(context_); | |
171 #if defined(OS_MACOSX) | |
172 if (plugin_handle_) { | |
173 Send(new ViewHostMsg_DestroyFakePluginWindowHandle(routing_id(), | |
174 plugin_handle_)); | |
175 } | |
176 #endif | |
177 } | |
191 } | 178 } |
192 | 179 |
193 WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() { | 180 void RenderWidgetFullscreenPepper::Invalidate() { |
194 return new PepperWidget(plugin_, this); | 181 InvalidateRect(gfx::Rect(size_.width(), size_.height())); |
195 } | 182 } |
196 | 183 |
197 void RenderWidgetFullscreenPepper::Close() { | 184 void RenderWidgetFullscreenPepper::InvalidateRect(const WebKit::WebRect& rect) { |
198 // If the fullscreen window is closed (e.g. user pressed escape), reset to | 185 if (CheckCompositing()) { |
199 // normal mode. | 186 scheduleComposite(); |
200 if (plugin_) | 187 } else { |
201 plugin_->SetFullscreen(false); | 188 didInvalidateRect(rect); |
189 } | |
190 } | |
191 | |
192 void RenderWidgetFullscreenPepper::ScrollRect( | |
193 int dx, int dy, const WebKit::WebRect& rect) { | |
194 if (CheckCompositing()) { | |
195 scheduleComposite(); | |
196 } else { | |
197 didScrollRect(dx, dy, rect); | |
198 } | |
199 } | |
200 | |
201 void RenderWidgetFullscreenPepper::Destroy() { | |
202 // This function is called by the plugin instance as it's going away, so reset | |
203 // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close(). | |
204 plugin_ = NULL; | |
205 Send(new ViewHostMsg_Close(routing_id_)); | |
206 } | |
207 | |
208 webkit::ppapi::PluginDelegate::PlatformContext3D* | |
209 RenderWidgetFullscreenPepper::CreateContext3D() { | |
210 if (!context_) { | |
211 CreateContext(); | |
212 } | |
213 if (!context_) | |
214 return NULL; | |
215 return new PlatformContext3DImpl(context_); | |
202 } | 216 } |
203 | 217 |
204 void RenderWidgetFullscreenPepper::DidInitiatePaint() { | 218 void RenderWidgetFullscreenPepper::DidInitiatePaint() { |
205 if (plugin_) | 219 if (plugin_) |
206 plugin_->ViewInitiatedPaint(); | 220 plugin_->ViewInitiatedPaint(); |
207 } | 221 } |
208 | 222 |
209 void RenderWidgetFullscreenPepper::DidFlushPaint() { | 223 void RenderWidgetFullscreenPepper::DidFlushPaint() { |
210 if (plugin_) | 224 if (plugin_) |
211 plugin_->ViewFlushedPaint(); | 225 plugin_->ViewFlushedPaint(); |
212 } | 226 } |
213 | 227 |
214 void RenderWidgetFullscreenPepper::SendClose() { | 228 void RenderWidgetFullscreenPepper::Close() { |
215 // This function is called by the plugin instance as it's going away, so reset | 229 // If the fullscreen window is closed (e.g. user pressed escape), reset to |
216 // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close(). | 230 // normal mode. |
217 plugin_ = NULL; | 231 if (plugin_) |
218 Send(new ViewHostMsg_Close(routing_id_)); | 232 plugin_->SetFullscreen(false); |
219 } | |
220 | |
221 void RenderWidgetFullscreenPepper::GenerateFullRepaint() { | |
222 didInvalidateRect(gfx::Rect(size_.width(), size_.height())); | |
223 } | 233 } |
224 | 234 |
225 webkit::ppapi::PluginInstance* | 235 webkit::ppapi::PluginInstance* |
226 RenderWidgetFullscreenPepper::GetBitmapForOptimizedPluginPaint( | 236 RenderWidgetFullscreenPepper::GetBitmapForOptimizedPluginPaint( |
227 const gfx::Rect& paint_bounds, | 237 const gfx::Rect& paint_bounds, |
228 TransportDIB** dib, | 238 TransportDIB** dib, |
229 gfx::Rect* location, | 239 gfx::Rect* location, |
230 gfx::Rect* clip) { | 240 gfx::Rect* clip) { |
231 if (plugin_ && | 241 if (plugin_ && |
232 plugin_->GetBitmapForOptimizedPluginPaint(paint_bounds, dib, | 242 plugin_->GetBitmapForOptimizedPluginPaint(paint_bounds, dib, |
233 location, clip)) | 243 location, clip)) |
234 return plugin_; | 244 return plugin_; |
235 return NULL; | 245 return NULL; |
236 } | 246 } |
247 | |
248 void RenderWidgetFullscreenPepper::OnResize(const gfx::Size& size, | |
249 const gfx::Rect& resizer_rect) { | |
250 if (context_) { | |
251 #if defined(OS_MACOSX) | |
252 ggl::ResizeOnscreenContext(context_, size); | |
253 #else | |
254 gpu::gles2::GLES2Implementation* gl = ggl::GetImplementation(context_); | |
255 gl->ResizeCHROMIUM(size.width(), size.height()); | |
256 #endif | |
257 gl->Viewport(0, 0, size.width(), size.height()); | |
258 } | |
259 RenderWidget::OnResize(size, resizer_rect); | |
260 } | |
261 | |
262 WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() { | |
263 return new PepperWidget(plugin_, this); | |
264 } | |
265 | |
266 void RenderWidgetFullscreenPepper::CreateContext() { | |
267 DCHECK(!context_); | |
268 RenderThread* render_thread = RenderThread::current(); | |
269 DCHECK(render_thread); | |
270 GpuChannelHost* host = render_thread->EstablishGpuChannelSync(); | |
271 if (!host) | |
272 return; | |
273 gfx::NativeViewId view_id; | |
274 #if !defined(OS_MACOSX) | |
275 view_id = host_window(); | |
276 #else | |
277 Send(new ViewHostMsg_AllocateFakePluginWindowHandle( | |
278 routing_id(), true, true, &plugin_handle_)); | |
279 if (!plugin_handle_) | |
280 return; | |
281 view_id = static_cast<gfx::NativeViewId>(plugin_handle_); | |
282 #endif | |
283 const int32 attribs[] = { | |
284 ggl::GGL_ALPHA_SIZE, 8, | |
285 ggl::GGL_DEPTH_SIZE, 0, | |
286 ggl::GGL_STENCIL_SIZE, 0, | |
287 ggl::GGL_SAMPLES, 0, | |
288 ggl::GGL_SAMPLE_BUFFERS, 0, | |
289 ggl::GGL_NONE, | |
290 }; | |
291 context_ = ggl::CreateViewContext( | |
292 host, | |
293 view_id, | |
294 routing_id(), | |
295 "GL_OES_packed_depth_stencil GL_OES_depth24", | |
296 attribs); | |
297 if (!InitContext()) { | |
298 ggl::DestroyContext(context_); | |
299 context_ = NULL; | |
300 } | |
301 if (!context_) { | |
302 #if defined(OS_MACOSX) | |
303 Send(new ViewHostMsg_DestroyFakePluginWindowHandle(routing_id(), | |
304 plugin_handle_)); | |
305 plugin_handle_ = NULL; | |
306 #endif | |
307 return; | |
308 } | |
309 ggl::SetSwapBuffersCallback( | |
310 context_, | |
311 NewCallback(this, &RenderWidgetFullscreenPepper::DidFlushPaint)); | |
312 } | |
313 | |
314 namespace { | |
315 | |
316 const char kVertexShader[] = | |
317 "attribute vec2 in_tex_coord;\n" | |
318 "varying vec2 tex_coord;\n" | |
319 "void main() {\n" | |
320 " gl_Position = vec4(in_tex_coord.x * 2. - 1.,\n" | |
321 " in_tex_coord.y * 2. - 1.,\n" | |
322 " 0.,\n" | |
323 " 1.);\n" | |
324 " tex_coord = vec2(in_tex_coord.x, 1. - in_tex_coord.y);\n" | |
325 "}\n"; | |
326 | |
327 const char kFragmentShader[] = | |
328 "precision mediump float;\n" | |
329 "varying vec2 tex_coord;\n" | |
330 "uniform sampler2D in_texture;\n" | |
331 "void main() {\n" | |
332 " gl_FragColor = texture2D(in_texture, tex_coord);\n" | |
333 "}\n"; | |
334 | |
335 GLuint CreateShaderFromSource(gpu::gles2::GLES2Implementation* gl, | |
336 GLenum type, | |
337 const char* source) { | |
338 GLuint shader = gl->CreateShader(type); | |
339 gl->ShaderSource(shader, 1, &source, NULL); | |
340 gl->CompileShader(shader); | |
341 int status; | |
342 gl->GetShaderiv(shader, GL_COMPILE_STATUS, &status); | |
343 if (!status) { | |
344 int size = 0; | |
345 gl->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &size); | |
346 scoped_array<char> log(new char[size]); | |
347 gl->GetShaderInfoLog(shader, size, NULL, log.get()); | |
348 DLOG(ERROR) << "Compilation failed: " << log.get(); | |
349 gl->DeleteShader(shader); | |
350 shader = 0; | |
351 } | |
352 return shader; | |
353 } | |
354 | |
355 float kTexCoords[] = { | |
apatrick
2011/01/06 02:59:31
const float?
piman
2011/01/06 04:27:46
Done.
| |
356 0.f, 0.f, | |
357 0.f, 2.f, | |
358 2.f, 0.f, | |
359 }; | |
360 | |
361 } // anonymous namespace | |
362 | |
363 bool RenderWidgetFullscreenPepper::InitContext() { | |
364 gpu::gles2::GLES2Implementation* gl = ggl::GetImplementation(context_); | |
365 program_ = gl->CreateProgram(); | |
apatrick
2011/01/06 02:59:31
You're relying on the context being destroyed to d
piman
2011/01/06 04:27:46
Done.
I was relying on the context destruction, a
| |
366 | |
367 GLuint vertex_shader = | |
368 CreateShaderFromSource(gl, GL_VERTEX_SHADER, kVertexShader); | |
369 if (!vertex_shader) | |
370 return false; | |
371 gl->AttachShader(program_, vertex_shader); | |
372 gl->DeleteShader(vertex_shader); | |
373 | |
374 GLuint fragment_shader = | |
375 CreateShaderFromSource(gl, GL_FRAGMENT_SHADER, kFragmentShader); | |
376 if (!fragment_shader) | |
377 return false; | |
378 gl->AttachShader(program_, fragment_shader); | |
379 gl->DeleteShader(fragment_shader); | |
380 | |
381 gl->BindAttribLocation(program_, 0, "in_tex_coord"); | |
382 gl->LinkProgram(program_); | |
383 int status; | |
384 gl->GetProgramiv(program_, GL_LINK_STATUS, &status); | |
385 if (!status) { | |
386 int size = 0; | |
387 gl->GetProgramiv(program_, GL_INFO_LOG_LENGTH, &size); | |
388 scoped_array<char> log(new char[size]); | |
389 gl->GetProgramInfoLog(program_, size, NULL, log.get()); | |
390 DLOG(ERROR) << "Link failed: " << log.get(); | |
391 return false; | |
392 } | |
393 gl->UseProgram(program_); | |
394 int texture_location = gl->GetUniformLocation(program_, "in_texture"); | |
395 gl->Uniform1i(texture_location, 0); | |
396 | |
397 gl->GenBuffers(1, &buffer_); | |
398 gl->BindBuffer(GL_ARRAY_BUFFER, buffer_); | |
399 gl->BufferData(GL_ARRAY_BUFFER, | |
400 sizeof(kTexCoords), | |
401 kTexCoords, | |
402 GL_STATIC_DRAW); | |
403 gl->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); | |
404 gl->EnableVertexAttribArray(0); | |
405 return true; | |
406 } | |
407 | |
408 bool RenderWidgetFullscreenPepper::CheckCompositing() { | |
409 bool compositing = webwidget_->isAcceleratedCompositingActive(); | |
410 if (compositing != is_accelerated_compositing_active_) { | |
411 didActivateAcceleratedCompositing(compositing); | |
412 } | |
413 return compositing; | |
414 } | |
OLD | NEW |