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