diff --git a/libcef/browser/render_widget_host_view_osr.cc b/libcef/browser/render_widget_host_view_osr.cc index 798b0ab8f..3bf4e57c9 100644 --- a/libcef/browser/render_widget_host_view_osr.cc +++ b/libcef/browser/render_widget_host_view_osr.cc @@ -274,13 +274,21 @@ void CefRenderWidgetHostViewOSR::OnSwapCompositorFrame( } if (frame->delegated_frame_data) { + // Determine the damage rectangle for the current frame. This is the same + // calculation that SwapDelegatedFrame uses. + cc::RenderPass* root_pass = + frame->delegated_frame_data->render_pass_list.back(); + gfx::Size frame_size = root_pass->output_rect.size(); + gfx::Rect damage_rect = gfx::ToEnclosingRect(root_pass->damage_rect); + damage_rect.Intersect(gfx::Rect(frame_size)); + delegated_frame_host_->SwapDelegatedFrame( output_surface_id, frame->delegated_frame_data.Pass(), frame->metadata.device_scale_factor, frame->metadata.latency_info); - GenerateFrame(true); + GenerateFrame(true, damage_rect); return; } @@ -699,8 +707,8 @@ void CefRenderWidgetHostViewOSR::Invalidate( popup_host_view_->Invalidate(type); return; } - - GenerateFrame(true); + + GenerateFrame(true, root_layer_->bounds()); } void CefRenderWidgetHostViewOSR::SendKeyEvent( @@ -829,7 +837,9 @@ void CefRenderWidgetHostViewOSR::ResizeRootLayer() { compositor_->SetScaleAndSize(CurrentDeviceScaleFactor(), size); } -void CefRenderWidgetHostViewOSR::GenerateFrame(bool force_frame) { +void CefRenderWidgetHostViewOSR::GenerateFrame( + bool force_frame, + const gfx::Rect& damage_rect) { if (force_frame && !frame_pending_) frame_pending_ = true; @@ -837,6 +847,10 @@ void CefRenderWidgetHostViewOSR::GenerateFrame(bool force_frame) { if (!frame_pending_) return; + // Keep track of |damage_rect| for when the next frame is generated. + if (!damage_rect.IsEmpty()) + pending_damage_rect_.Union(damage_rect); + // Don't attempt to generate a frame while one is currently in-progress. if (frame_in_progress_) return; @@ -864,13 +878,17 @@ void CefRenderWidgetHostViewOSR::InternalGenerateFrame() { if (!render_widget_host_) return; + const gfx::Rect damage_rect = pending_damage_rect_; + pending_damage_rect_.SetRect(0, 0, 0, 0); + // The below code is similar in functionality to // DelegatedFrameHost::CopyFromCompositingSurface but we reuse the same // SkBitmap in the GPU codepath and avoid scaling where possible. scoped_ptr request = cc::CopyOutputRequest::CreateRequest(base::Bind( &CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceHasResult, - weak_ptr_factory_.GetWeakPtr())); + weak_ptr_factory_.GetWeakPtr(), + damage_rect)); const gfx::Rect& src_subrect_in_pixel = content::ConvertRectToPixel(CurrentDeviceScaleFactor(), @@ -880,27 +898,30 @@ void CefRenderWidgetHostViewOSR::InternalGenerateFrame() { } void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceHasResult( + const gfx::Rect& damage_rect, scoped_ptr result) { if (result->IsEmpty() || result->size().IsEmpty() || !render_widget_host_) { - OnFrameCaptureFailure(); + OnFrameCaptureFailure(damage_rect); return; } if (result->HasTexture()) { - PrepareTextureCopyOutputResult(result.Pass()); + PrepareTextureCopyOutputResult(damage_rect, result.Pass()); return; } DCHECK(result->HasBitmap()); - PrepareBitmapCopyOutputResult(result.Pass()); + PrepareBitmapCopyOutputResult(damage_rect, result.Pass()); } void CefRenderWidgetHostViewOSR::PrepareTextureCopyOutputResult( + const gfx::Rect& damage_rect, scoped_ptr result) { DCHECK(result->HasTexture()); base::ScopedClosureRunner scoped_callback_runner( base::Bind(&CefRenderWidgetHostViewOSR::OnFrameCaptureFailure, - weak_ptr_factory_.GetWeakPtr())); + weak_ptr_factory_.GetWeakPtr(), + damage_rect)); const gfx::Size& result_size = result->size(); SkIRect bitmap_size; @@ -950,6 +971,7 @@ void CefRenderWidgetHostViewOSR::PrepareTextureCopyOutputResult( &CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinishedProxy, weak_ptr_factory_.GetWeakPtr(), base::Passed(&release_callback), + damage_rect, base::Passed(&bitmap_), base::Passed(&bitmap_pixels_lock)), content::GLHelper::SCALER_QUALITY_FAST); @@ -959,6 +981,7 @@ void CefRenderWidgetHostViewOSR::PrepareTextureCopyOutputResult( void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinishedProxy( base::WeakPtr view, scoped_ptr release_callback, + const gfx::Rect& damage_rect, scoped_ptr bitmap, scoped_ptr bitmap_pixels_lock, bool result) { @@ -974,7 +997,7 @@ void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinishedProxy( if (view) { view->CopyFromCompositingSurfaceFinished( - bitmap.Pass(), bitmap_pixels_lock.Pass(), result); + damage_rect, bitmap.Pass(), bitmap_pixels_lock.Pass(), result); } else { bitmap_pixels_lock.reset(); bitmap.reset(); @@ -982,6 +1005,7 @@ void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinishedProxy( } void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinished( + const gfx::Rect& damage_rect, scoped_ptr bitmap, scoped_ptr bitmap_pixels_lock, bool result) { @@ -990,14 +1014,15 @@ void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinished( bitmap_ = bitmap.Pass(); if (result) { - OnFrameCaptureSuccess(*bitmap_, bitmap_pixels_lock.Pass()); + OnFrameCaptureSuccess(damage_rect, *bitmap_, bitmap_pixels_lock.Pass()); } else { bitmap_pixels_lock.reset(); - OnFrameCaptureFailure(); + OnFrameCaptureFailure(damage_rect); } } void CefRenderWidgetHostViewOSR::PrepareBitmapCopyOutputResult( + const gfx::Rect& damage_rect, scoped_ptr result) { DCHECK(result->HasBitmap()); scoped_ptr source = result->TakeBitmap(); @@ -1005,33 +1030,39 @@ void CefRenderWidgetHostViewOSR::PrepareBitmapCopyOutputResult( if (source) { scoped_ptr bitmap_pixels_lock( new SkAutoLockPixels(*source)); - OnFrameCaptureSuccess(*source, bitmap_pixels_lock.Pass()); + OnFrameCaptureSuccess(damage_rect, *source, bitmap_pixels_lock.Pass()); } else { - OnFrameCaptureFailure(); + OnFrameCaptureFailure(damage_rect); } } -void CefRenderWidgetHostViewOSR::OnFrameCaptureFailure() { +void CefRenderWidgetHostViewOSR::OnFrameCaptureFailure( + const gfx::Rect& damage_rect) { + // Retry with the same |damage_rect|. + pending_damage_rect_.Union(damage_rect); + const bool force_frame = (++frame_retry_count_ <= kFrameRetryLimit); OnFrameCaptureCompletion(force_frame); } void CefRenderWidgetHostViewOSR::OnFrameCaptureSuccess( + const gfx::Rect& damage_rect, const SkBitmap& bitmap, scoped_ptr bitmap_pixels_lock) { - SkRect bounds; - bitmap.getBounds(&bounds); + gfx::Rect rect_in_bitmap(0, 0, bitmap.width(), bitmap.height()); + rect_in_bitmap.Intersect(damage_rect); CefRenderHandler::RectList rcList; - rcList.push_back(CefRect(0, 0, bounds.width(), bounds.height())); + rcList.push_back(CefRect(rect_in_bitmap.x(), rect_in_bitmap.y(), + rect_in_bitmap.width(), rect_in_bitmap.height())); browser_impl_->GetClient()->GetRenderHandler()->OnPaint( browser_impl_.get(), IsPopupWidget() ? PET_POPUP : PET_VIEW, rcList, bitmap.getPixels(), - bounds.width(), - bounds.height()); + bitmap.width(), + bitmap.height()); bitmap_pixels_lock.reset(); @@ -1050,7 +1081,9 @@ void CefRenderWidgetHostViewOSR::OnFrameCaptureCompletion(bool force_frame) { // Generate the pending frame now. CEF_POST_TASK(CEF_UIT, base::Bind(&CefRenderWidgetHostViewOSR::GenerateFrame, - weak_ptr_factory_.GetWeakPtr(), force_frame)); + weak_ptr_factory_.GetWeakPtr(), + force_frame, + gfx::Rect())); } } diff --git a/libcef/browser/render_widget_host_view_osr.h b/libcef/browser/render_widget_host_view_osr.h index 5a405de36..78c0b1d03 100644 --- a/libcef/browser/render_widget_host_view_osr.h +++ b/libcef/browser/render_widget_host_view_osr.h @@ -249,26 +249,32 @@ class CefRenderWidgetHostViewOSR // Implementation based on RendererOverridesHandler::InnerSwapCompositorFrame // and DelegatedFrameHost::CopyFromCompositingSurface. - void GenerateFrame(bool force_frame); + void GenerateFrame(bool force_frame, const gfx::Rect& damage_rect); void InternalGenerateFrame(); void CopyFromCompositingSurfaceHasResult( + const gfx::Rect& damage_rect, scoped_ptr result); void PrepareTextureCopyOutputResult( + const gfx::Rect& damage_rect, scoped_ptr result); static void CopyFromCompositingSurfaceFinishedProxy( base::WeakPtr view, scoped_ptr release_callback, + const gfx::Rect& damage_rect, scoped_ptr bitmap, scoped_ptr bitmap_pixels_lock, bool result); void CopyFromCompositingSurfaceFinished( + const gfx::Rect& damage_rect, scoped_ptr bitmap, scoped_ptr bitmap_pixels_lock, bool result); void PrepareBitmapCopyOutputResult( + const gfx::Rect& damage_rect, scoped_ptr result); - void OnFrameCaptureFailure(); + void OnFrameCaptureFailure(const gfx::Rect& damage_rect); void OnFrameCaptureSuccess( + const gfx::Rect& damage_rect, const SkBitmap& bitmap, scoped_ptr bitmap_pixels_lock); void OnFrameCaptureCompletion(bool force_frame); @@ -323,6 +329,7 @@ class CefRenderWidgetHostViewOSR bool frame_in_progress_; int frame_retry_count_; scoped_ptr bitmap_; + gfx::Rect pending_damage_rect_; bool hold_resize_; bool pending_resize_; diff --git a/tests/cefclient/cefclient_gtk.cpp b/tests/cefclient/cefclient_gtk.cpp index 6047e1c83..2405a7244 100644 --- a/tests/cefclient/cefclient_gtk.cpp +++ b/tests/cefclient/cefclient_gtk.cpp @@ -545,12 +545,15 @@ int main(int argc, char* argv[]) { if (AppIsOffScreenRenderingEnabled()) { CefRefPtr cmd_line = AppGetCommandLine(); - bool transparent = + const bool transparent = cmd_line->HasSwitch(cefclient::kTransparentPaintingEnabled); + const bool show_update_rect = + cmd_line->HasSwitch(cefclient::kShowUpdateRect); // Create the GTKGL surface. CefRefPtr osr_window = - OSRWindow::Create(&g_main_browser_provider, transparent, vbox); + OSRWindow::Create(&g_main_browser_provider, transparent, + show_update_rect, vbox); // Show the GTK window. gtk_widget_show_all(GTK_WIDGET(window)); diff --git a/tests/cefclient/cefclient_mac.mm b/tests/cefclient/cefclient_mac.mm index 704a7dd90..afac2e6f6 100644 --- a/tests/cefclient/cefclient_mac.mm +++ b/tests/cefclient/cefclient_mac.mm @@ -488,11 +488,14 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { if (AppIsOffScreenRenderingEnabled()) { CefRefPtr cmd_line = AppGetCommandLine(); - bool transparent = + const bool transparent = cmd_line->HasSwitch(cefclient::kTransparentPaintingEnabled); + const bool show_update_rect = + cmd_line->HasSwitch(cefclient::kShowUpdateRect); CefRefPtr osr_window = - OSRWindow::Create(&g_main_browser_provider, transparent, contentView, + OSRWindow::Create(&g_main_browser_provider, transparent, + show_update_rect, contentView, CefRect(0, 0, kWindowWidth, kWindowHeight)); window_info.SetAsWindowless(osr_window->GetWindowHandle(), transparent); g_handler->SetOSRHandler(osr_window->GetRenderHandler().get()); diff --git a/tests/cefclient/cefclient_osr_widget_gtk.cpp b/tests/cefclient/cefclient_osr_widget_gtk.cpp index 5db6166d5..a2b43df37 100644 --- a/tests/cefclient/cefclient_osr_widget_gtk.cpp +++ b/tests/cefclient/cefclient_osr_widget_gtk.cpp @@ -1096,12 +1096,14 @@ class ScopedGLContext { // static CefRefPtr OSRWindow::Create(OSRBrowserProvider* browser_provider, bool transparent, + bool show_update_rect, ClientWindowHandle parentView) { DCHECK(browser_provider); if (!browser_provider) return NULL; - return new OSRWindow(browser_provider, transparent, parentView); + return new OSRWindow(browser_provider, transparent, show_update_rect, + parentView); } // static @@ -1241,8 +1243,9 @@ void OSRWindow::ApplyPopupOffset(int& x, int& y) const { OSRWindow::OSRWindow(OSRBrowserProvider* browser_provider, bool transparent, + bool show_update_rect, ClientWindowHandle parentView) - : renderer_(transparent), + : renderer_(transparent, show_update_rect), browser_provider_(browser_provider), gl_enabled_(false), painting_popup_(false), diff --git a/tests/cefclient/cefclient_osr_widget_gtk.h b/tests/cefclient/cefclient_osr_widget_gtk.h index e79a3fa79..c2e01f557 100644 --- a/tests/cefclient/cefclient_osr_widget_gtk.h +++ b/tests/cefclient/cefclient_osr_widget_gtk.h @@ -24,6 +24,7 @@ class OSRWindow : public ClientHandler::RenderHandler { // object. static CefRefPtr Create(OSRBrowserProvider* browser_provider, bool transparent, + bool show_update_rect, ClientWindowHandle parentView); static CefRefPtr From( @@ -73,6 +74,7 @@ class OSRWindow : public ClientHandler::RenderHandler { private: OSRWindow(OSRBrowserProvider* browser_provider, bool transparent, + bool show_update_rect, ClientWindowHandle parentView); virtual ~OSRWindow(); diff --git a/tests/cefclient/cefclient_osr_widget_mac.h b/tests/cefclient/cefclient_osr_widget_mac.h index 30e48e096..f2ee675a4 100644 --- a/tests/cefclient/cefclient_osr_widget_mac.h +++ b/tests/cefclient/cefclient_osr_widget_mac.h @@ -42,7 +42,8 @@ class OSRBrowserProvider { id endWheelMonitor_; } -- (id)initWithFrame:(NSRect)frame andTransparency:(bool)transparency; +- (id)initWithFrame:(NSRect)frame andTransparency:(bool)transparency + andShowUpdateRect:(bool)show_update_rect; - (NSPoint)getClickPointForEvent:(NSEvent*)event; - (void)getKeyEvent:(CefKeyEvent&)keyEvent forEvent:(NSEvent*)event; - (void)getMouseEvent:(CefMouseEvent&)mouseEvent forEvent:(NSEvent*)event; @@ -122,6 +123,7 @@ class OSRWindow { public: static CefRefPtr Create(OSRBrowserProvider* browser_provider, bool transparent, + bool show_update_rect, CefWindowHandle parentView, const CefRect& frame); @@ -134,6 +136,7 @@ class OSRWindow { private: OSRWindow(OSRBrowserProvider* browser_provider, bool transparent, + bool show_update_rect, CefWindowHandle parentView, const CefRect& frame); diff --git a/tests/cefclient/cefclient_osr_widget_mac.mm b/tests/cefclient/cefclient_osr_widget_mac.mm index c881320e8..18a0d6632 100644 --- a/tests/cefclient/cefclient_osr_widget_mac.mm +++ b/tests/cefclient/cefclient_osr_widget_mac.mm @@ -20,11 +20,13 @@ #include "cefclient/osrenderer.h" #include "cefclient/resource_util.h" +namespace { + // This method will return YES for OS X versions 10.7.3 and later, and NO // otherwise. // Used to prevent a crash when building with the 10.7 SDK and accessing the // notification below. See: http://crbug.com/260595. -static BOOL SupportsBackingPropertiesChangedNotification() { +BOOL SupportsBackingPropertiesChangedNotification() { // windowDidChangeBackingProperties: method has been added to the // NSWindowDelegate protocol in 10.7.3, at the same time as the // NSWindowDidChangeBackingPropertiesNotification notification was added. @@ -43,6 +45,25 @@ static BOOL SupportsBackingPropertiesChangedNotification() { return methodDescription.name != NULL || methodDescription.types != NULL; } +class ScopedGLContext { + public: + ScopedGLContext(ClientOpenGLView* view, bool swap_buffers) + : swap_buffers_(swap_buffers) { + context_ = [view openGLContext]; + [context_ makeCurrentContext]; + } + ~ScopedGLContext() { + [NSOpenGLContext clearCurrentContext]; + if (swap_buffers_) + [context_ flushBuffer]; + } + private: + NSOpenGLContext* context_; + const bool swap_buffers_; +}; + +} // namespace + @interface ClientOpenGLView () - (void)resetDragDrop; - (void)fillPasteboard; @@ -232,8 +253,7 @@ void ClientOSRHandler::OnPaint(CefRefPtr browser, return; } - NSOpenGLContext* context = [view_ openGLContext]; - [context makeCurrentContext]; + ScopedGLContext scoped_gl_context(view_, true); view_->renderer_->OnPaint(browser, type, dirtyRects, buffer, width, height); @@ -248,7 +268,6 @@ void ClientOSRHandler::OnPaint(CefRefPtr browser, } view_->renderer_->Render(); - [context flushBuffer]; } void ClientOSRHandler::OnCursorChange(CefRefPtr browser, @@ -286,7 +305,8 @@ void ClientOSRHandler::SetLoading(bool isLoading) { @synthesize was_last_mouse_down_on_view = was_last_mouse_down_on_view_; -- (id)initWithFrame:(NSRect)frame andTransparency:(bool)transparency { +- (id)initWithFrame:(NSRect)frame andTransparency:(bool)transparency + andShowUpdateRect:(bool)show_update_rect { NSOpenGLPixelFormat * pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:(NSOpenGLPixelFormatAttribute[]) { @@ -299,7 +319,7 @@ void ClientOSRHandler::SetLoading(bool isLoading) { self = [super initWithFrame:frame pixelFormat:pixelFormat]; if (self) { - renderer_ = new ClientOSRenderer(transparency); + renderer_ = new ClientOSRenderer(transparency, show_update_rect); rotating_ = false; endWheelMonitor_ = nil; @@ -1191,18 +1211,23 @@ void ClientOSRHandler::SetLoading(bool isLoading) { CefRefPtr OSRWindow::Create(OSRBrowserProvider* browser_provider, bool transparent, + bool show_update_rect, CefWindowHandle parentView, const CefRect& frame) { - return new OSRWindow(browser_provider, transparent, parentView, frame); + return new OSRWindow(browser_provider, transparent, show_update_rect, + parentView, frame); } OSRWindow::OSRWindow(OSRBrowserProvider* browser_provider, bool transparent, + bool show_update_rect, CefWindowHandle parentView, const CefRect& frame) { NSRect window_rect = NSMakeRect(frame.x, frame.y, frame.width, frame.height); - ClientOpenGLView* view = [[ClientOpenGLView alloc] initWithFrame:window_rect - andTransparency:transparent]; + ClientOpenGLView* view = + [[ClientOpenGLView alloc] initWithFrame:window_rect + andTransparency:transparent + andShowUpdateRect:show_update_rect]; this->view_ = view; [parentView addSubview:view]; [view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; diff --git a/tests/cefclient/cefclient_osr_widget_win.cpp b/tests/cefclient/cefclient_osr_widget_win.cpp index feecbfc7e..a59cc38ac 100644 --- a/tests/cefclient/cefclient_osr_widget_win.cpp +++ b/tests/cefclient/cefclient_osr_widget_win.cpp @@ -10,14 +10,42 @@ #include "include/wrapper/cef_closure_task.h" #include "cefclient/resource.h" +namespace { + +class ScopedGLContext { + public: + ScopedGLContext(HDC hdc, HGLRC hglrc, bool swap_buffers) + : hdc_(hdc), + swap_buffers_(swap_buffers) { + BOOL result = wglMakeCurrent(hdc, hglrc); + DCHECK(result); + } + ~ScopedGLContext() { + BOOL result = wglMakeCurrent(NULL, NULL); + DCHECK(result); + if (swap_buffers_) { + result = SwapBuffers(hdc_); + DCHECK(result); + } + } + + private: + const HDC hdc_; + const bool swap_buffers_; +}; + +} // namespace + // static -CefRefPtr OSRWindow::Create(OSRBrowserProvider* browser_provider, - bool transparent) { +CefRefPtr OSRWindow::Create( + OSRBrowserProvider* browser_provider, + bool transparent, + bool show_update_rect) { DCHECK(browser_provider); if (!browser_provider) return NULL; - return new OSRWindow(browser_provider, transparent); + return new OSRWindow(browser_provider, transparent, show_update_rect); } // static @@ -135,15 +163,16 @@ void OSRWindow::OnPaint(CefRefPtr browser, if (!hDC_) EnableGL(); - wglMakeCurrent(hDC_, hRC_); - renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height); - if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) { - painting_popup_ = true; - browser->GetHost()->Invalidate(PET_POPUP); - painting_popup_ = false; + { + ScopedGLContext scoped_gl_context(hDC_, hRC_, true); + renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height); + if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) { + painting_popup_ = true; + browser->GetHost()->Invalidate(PET_POPUP); + painting_popup_ = false; + } + renderer_.Render(); } - renderer_.Render(); - SwapBuffers(hDC_); } void OSRWindow::OnCursorChange(CefRefPtr browser, @@ -249,8 +278,10 @@ CefBrowserHost::DragOperationsMask #endif // defined(CEF_USE_ATL) -OSRWindow::OSRWindow(OSRBrowserProvider* browser_provider, bool transparent) - : renderer_(transparent), +OSRWindow::OSRWindow(OSRBrowserProvider* browser_provider, + bool transparent, + bool show_update_rect) + : renderer_(transparent, show_update_rect), browser_provider_(browser_provider), hWnd_(NULL), hDC_(NULL), @@ -275,9 +306,8 @@ void OSRWindow::Render() { if (!hDC_) EnableGL(); - wglMakeCurrent(hDC_, hRC_); + ScopedGLContext scoped_gl_context(hDC_, hRC_, true); renderer_.Render(); - SwapBuffers(hDC_); } void OSRWindow::EnableGL() { @@ -303,8 +333,8 @@ void OSRWindow::EnableGL() { // Create and enable the render context. hRC_ = wglCreateContext(hDC_); - wglMakeCurrent(hDC_, hRC_); + ScopedGLContext scoped_gl_context(hDC_, hRC_, false); renderer_.Initialize(); } @@ -314,11 +344,15 @@ void OSRWindow::DisableGL() { if (!hDC_) return; - renderer_.Cleanup(); + { + ScopedGLContext scoped_gl_context(hDC_, hRC_, false); + renderer_.Cleanup(); + } if (IsWindow(hWnd_)) { - wglMakeCurrent(NULL, NULL); - wglDeleteContext(hRC_); + // wglDeleteContext will make the context not current before deleting it. + BOOL result = wglDeleteContext(hRC_); + DCHECK(result); ReleaseDC(hWnd_, hDC_); } diff --git a/tests/cefclient/cefclient_osr_widget_win.h b/tests/cefclient/cefclient_osr_widget_win.h index c28467b1a..5a0dc3fb7 100644 --- a/tests/cefclient/cefclient_osr_widget_win.h +++ b/tests/cefclient/cefclient_osr_widget_win.h @@ -28,7 +28,8 @@ class OSRWindow : public ClientHandler::RenderHandler // Create a new OSRWindow instance. |browser_provider| must outlive this // object. static CefRefPtr Create(OSRBrowserProvider* browser_provider, - bool transparent); + bool transparent, + bool show_update_rect); static CefRefPtr From( CefRefPtr renderHandler); @@ -100,7 +101,9 @@ class OSRWindow : public ClientHandler::RenderHandler static int GetCefMouseModifiers(WPARAM wparam); private: - OSRWindow(OSRBrowserProvider* browser_provider, bool transparent); + OSRWindow(OSRBrowserProvider* browser_provider, + bool transparent, + bool show_update_rect); virtual ~OSRWindow(); void Render(); diff --git a/tests/cefclient/cefclient_win.cpp b/tests/cefclient/cefclient_win.cpp index 7b57b44e6..a3099a7bd 100644 --- a/tests/cefclient/cefclient_win.cpp +++ b/tests/cefclient/cefclient_win.cpp @@ -463,11 +463,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, if (AppIsOffScreenRenderingEnabled()) { CefRefPtr cmd_line = AppGetCommandLine(); - bool transparent = + const bool transparent = cmd_line->HasSwitch(cefclient::kTransparentPaintingEnabled); + const bool show_update_rect = + cmd_line->HasSwitch(cefclient::kShowUpdateRect); CefRefPtr osr_window = - OSRWindow::Create(&g_main_browser_provider, transparent); + OSRWindow::Create(&g_main_browser_provider, transparent, + show_update_rect); osr_window->CreateWidget(hWnd, rect, hInst, szOSRWindowClass); info.SetAsWindowless(osr_window->hwnd(), transparent); g_handler->SetOSRHandler(osr_window.get()); diff --git a/tests/cefclient/client_switches.cpp b/tests/cefclient/client_switches.cpp index 393c21f67..4e294d2dc 100644 --- a/tests/cefclient/client_switches.cpp +++ b/tests/cefclient/client_switches.cpp @@ -24,6 +24,7 @@ const char kUrl[] = "url"; const char kOffScreenRenderingEnabled[] = "off-screen-rendering-enabled"; const char kOffScreenFrameRate[] = "off-screen-frame-rate"; const char kTransparentPaintingEnabled[] = "transparent-painting-enabled"; +const char kShowUpdateRect[] = "show-update-rect"; const char kMouseCursorChangeDisabled[] = "mouse-cursor-change-disabled"; } // namespace cefclient diff --git a/tests/cefclient/client_switches.h b/tests/cefclient/client_switches.h index 25d109b4f..2eb2202ea 100644 --- a/tests/cefclient/client_switches.h +++ b/tests/cefclient/client_switches.h @@ -16,6 +16,7 @@ extern const char kUrl[]; extern const char kOffScreenRenderingEnabled[]; extern const char kOffScreenFrameRate[]; extern const char kTransparentPaintingEnabled[]; +extern const char kShowUpdateRect[]; extern const char kMouseCursorChangeDisabled[]; } // namespace cefclient diff --git a/tests/cefclient/osrenderer.cpp b/tests/cefclient/osrenderer.cpp index 6aaa96f13..f649a2613 100644 --- a/tests/cefclient/osrenderer.cpp +++ b/tests/cefclient/osrenderer.cpp @@ -28,9 +28,21 @@ #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 #endif +// DCHECK on gl errors. +#ifndef NDEBUG +#define VERIFY_NO_ERROR { \ + int _gl_error = glGetError(); \ + DCHECK(_gl_error == GL_NO_ERROR) << \ + "glGetError returned " << _gl_error; \ + } +#else +#define VERIFY_NO_ERROR +#endif -ClientOSRenderer::ClientOSRenderer(bool transparent) +ClientOSRenderer::ClientOSRenderer(bool transparent, + bool show_update_rect) : transparent_(transparent), + show_update_rect_(show_update_rect), initialized_(false), texture_id_(0), view_width_(0), @@ -47,21 +59,23 @@ void ClientOSRenderer::Initialize() { if (initialized_) return; - glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); + glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); VERIFY_NO_ERROR; - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); VERIFY_NO_ERROR; // Necessary for non-power-of-2 textures to render correctly. - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); VERIFY_NO_ERROR; // Create the texture. - glGenTextures(1, &texture_id_); - DCHECK_NE(texture_id_, 0U); + glGenTextures(1, &texture_id_); VERIFY_NO_ERROR; + DCHECK_NE(texture_id_, 0U); VERIFY_NO_ERROR; - glBindTexture(GL_TEXTURE_2D, texture_id_); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBindTexture(GL_TEXTURE_2D, texture_id_); VERIFY_NO_ERROR; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_NEAREST); VERIFY_NO_ERROR; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_NEAREST); VERIFY_NO_ERROR; + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); VERIFY_NO_ERROR; initialized_ = true; } @@ -87,19 +101,19 @@ void ClientOSRenderer::Render() { {0.0f, 0.0f, -1.0f, 1.0f, 0.0f} }; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); VERIFY_NO_ERROR; - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); VERIFY_NO_ERROR; + glLoadIdentity(); VERIFY_NO_ERROR; // Match GL units to screen coordinates. - glViewport(0, 0, view_width_, view_height_); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, 0, view_width_, view_height_, 0.1, 100.0); + glViewport(0, 0, view_width_, view_height_); VERIFY_NO_ERROR; + glMatrixMode(GL_PROJECTION); VERIFY_NO_ERROR; + glLoadIdentity(); VERIFY_NO_ERROR; // Draw the background gradient. - glPushAttrib(GL_ALL_ATTRIB_BITS); + glPushAttrib(GL_ALL_ATTRIB_BITS); VERIFY_NO_ERROR; + // Don't check for errors until glEnd(). glBegin(GL_QUADS); glColor4f(1.0, 0.0, 0.0, 1.0); // red glVertex2f(-1.0, -1.0); @@ -107,38 +121,78 @@ void ClientOSRenderer::Render() { glColor4f(0.0, 0.0, 1.0, 1.0); // blue glVertex2f(1.0, 1.0); glVertex2f(-1.0, 1.0); - glEnd(); - glPopAttrib(); + glEnd(); VERIFY_NO_ERROR; + glPopAttrib(); VERIFY_NO_ERROR; // Rotate the view based on the mouse spin. - if (spin_x_ != 0) - glRotatef(-spin_x_, 1.0f, 0.0f, 0.0f); - if (spin_y_ != 0) - glRotatef(-spin_y_, 0.0f, 1.0f, 0.0f); + if (spin_x_ != 0) { + glRotatef(-spin_x_, 1.0f, 0.0f, 0.0f); VERIFY_NO_ERROR; + } + if (spin_y_ != 0) { + glRotatef(-spin_y_, 0.0f, 1.0f, 0.0f); VERIFY_NO_ERROR; + } if (transparent_) { // Alpha blending style. Texture values have premultiplied alpha. - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); VERIFY_NO_ERROR; // Enable alpha blending. - glEnable(GL_BLEND); + glEnable(GL_BLEND); VERIFY_NO_ERROR; } // Enable 2D textures. - glEnable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_2D); VERIFY_NO_ERROR; // Draw the facets with the texture. - DCHECK_NE(texture_id_, 0U); - glBindTexture(GL_TEXTURE_2D, texture_id_); - glInterleavedArrays(GL_T2F_V3F, 0, vertices); - glDrawArrays(GL_QUADS, 0, 4); + DCHECK_NE(texture_id_, 0U); VERIFY_NO_ERROR; + glBindTexture(GL_TEXTURE_2D, texture_id_); VERIFY_NO_ERROR; + glInterleavedArrays(GL_T2F_V3F, 0, vertices); VERIFY_NO_ERROR; + glDrawArrays(GL_QUADS, 0, 4); VERIFY_NO_ERROR; // Disable 2D textures. - glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_2D); VERIFY_NO_ERROR; if (transparent_) { // Disable alpha blending. - glDisable(GL_BLEND); + glDisable(GL_BLEND); VERIFY_NO_ERROR; + } + + // Draw a rectangle around the update region. + if (show_update_rect_ && !update_rect_.IsEmpty()) { + int left = update_rect_.x; + int right = update_rect_.x + update_rect_.width; + int top = update_rect_.y; + int bottom = update_rect_.y + update_rect_.height; + +#if defined(OS_LINUX) + // Shrink the box so that top & right sides are drawn. + top += 1; + right -= 1; +#else + // Shrink the box so that left & bottom sides are drawn. + left += 1; + bottom -= 1; +#endif + + glPushAttrib(GL_ALL_ATTRIB_BITS); VERIFY_NO_ERROR + glMatrixMode(GL_PROJECTION); VERIFY_NO_ERROR; + glPushMatrix(); VERIFY_NO_ERROR; + glLoadIdentity(); VERIFY_NO_ERROR; + glOrtho(0, view_width_, view_height_, 0, 0, 1); VERIFY_NO_ERROR; + + glLineWidth(1); VERIFY_NO_ERROR; + glColor3f(1.0f, 0.0f, 0.0f); VERIFY_NO_ERROR; + // Don't check for errors until glEnd(). + glBegin(GL_LINE_STRIP); + glVertex2i(left, top); + glVertex2i(right, top); + glVertex2i(right, bottom); + glVertex2i(left, bottom); + glVertex2i(left, top); + glEnd(); VERIFY_NO_ERROR; + + glPopMatrix(); VERIFY_NO_ERROR; + glPopAttrib(); VERIFY_NO_ERROR; } } @@ -192,14 +246,14 @@ void ClientOSRenderer::OnPaint(CefRefPtr browser, if (transparent_) { // Enable alpha blending. - glEnable(GL_BLEND); + glEnable(GL_BLEND); VERIFY_NO_ERROR; } // Enable 2D textures. - glEnable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_2D); VERIFY_NO_ERROR; DCHECK_NE(texture_id_, 0U); - glBindTexture(GL_TEXTURE_2D, texture_id_); + glBindTexture(GL_TEXTURE_2D, texture_id_); VERIFY_NO_ERROR; if (type == PET_VIEW) { int old_width = view_width_; @@ -208,24 +262,30 @@ void ClientOSRenderer::OnPaint(CefRefPtr browser, view_width_ = width; view_height_ = height; - glPixelStorei(GL_UNPACK_ROW_LENGTH, view_width_); + if (show_update_rect_) + update_rect_ = dirtyRects[0]; - if (old_width != view_width_ || old_height != view_height_) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, view_width_); VERIFY_NO_ERROR; + + if (old_width != view_width_ || old_height != view_height_ || + (dirtyRects.size() == 1 && + dirtyRects[0] == CefRect(0, 0, view_width_, view_height_))) { // Update/resize the whole texture. - glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width_, view_height_, 0, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); VERIFY_NO_ERROR; + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); VERIFY_NO_ERROR; + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA, view_width_, view_height_, 0, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer); VERIFY_NO_ERROR; } else { // Update just the dirty rectangles. CefRenderHandler::RectList::const_iterator i = dirtyRects.begin(); for (; i != dirtyRects.end(); ++i) { const CefRect& rect = *i; - glPixelStorei(GL_UNPACK_SKIP_PIXELS, rect.x); - glPixelStorei(GL_UNPACK_SKIP_ROWS, rect.y); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, rect.x); VERIFY_NO_ERROR; + glPixelStorei(GL_UNPACK_SKIP_ROWS, rect.y); VERIFY_NO_ERROR; glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x, rect.y, rect.width, rect.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - buffer); + buffer); VERIFY_NO_ERROR; } } } else if (type == PET_POPUP && popup_rect_.width > 0 && @@ -250,19 +310,19 @@ void ClientOSRenderer::OnPaint(CefRefPtr browser, h -= y + h - view_height_; // Update the popup rectangle. - glPixelStorei(GL_UNPACK_ROW_LENGTH, width); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels); - glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows); + glPixelStorei(GL_UNPACK_ROW_LENGTH, width); VERIFY_NO_ERROR; + glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels); VERIFY_NO_ERROR; + glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows); VERIFY_NO_ERROR; glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, buffer); + GL_UNSIGNED_INT_8_8_8_8_REV, buffer); VERIFY_NO_ERROR; } // Disable 2D textures. - glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_2D); VERIFY_NO_ERROR; if (transparent_) { // Disable alpha blending. - glDisable(GL_BLEND); + glDisable(GL_BLEND); VERIFY_NO_ERROR; } } diff --git a/tests/cefclient/osrenderer.h b/tests/cefclient/osrenderer.h index 7bf585a3f..0a866a499 100644 --- a/tests/cefclient/osrenderer.h +++ b/tests/cefclient/osrenderer.h @@ -11,8 +11,8 @@ class ClientOSRenderer { public: - // The context must outlive this object. - explicit ClientOSRenderer(bool transparent); + ClientOSRenderer(bool transparent, + bool show_update_rect); virtual ~ClientOSRenderer(); // Initialize the OpenGL environment. @@ -50,7 +50,8 @@ class ClientOSRenderer { void ClearPopupRects(); private: - bool transparent_; + const bool transparent_; + const bool show_update_rect_; bool initialized_; unsigned int texture_id_; int view_width_; @@ -59,6 +60,7 @@ class ClientOSRenderer { CefRect original_popup_rect_; float spin_x_; float spin_y_; + CefRect update_rect_; }; #endif // CEF_TESTS_CEFCLIENT_OSRENDERER_H_