From e390fbe5b6a06c3c351280635ef60f08508007f3 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Tue, 21 Aug 2012 19:49:11 +0000 Subject: [PATCH] Merge revision 745 changes: - Improve the handling of invalidation/painting for off-screen rendering (issue #695). git-svn-id: https://chromiumembedded.googlecode.com/svn/branches/1025@746 5089003a-bbd8-11dd-ad1f-f1f9622dbc98 --- libcef/browser_impl.cc | 4 - libcef/browser_webview_delegate.cc | 4 +- libcef/browser_webview_mac.mm | 3 +- libcef/webview_host.cc | 5 + libcef/webview_host.h | 2 + libcef/webwidget_host.cc | 223 ++++++++++++++++++----------- libcef/webwidget_host.h | 63 +++----- libcef/webwidget_host_gtk.cc | 58 +++----- libcef/webwidget_host_mac.mm | 114 +++------------ libcef/webwidget_host_win.cc | 106 +++----------- tests/cefclient/osrenderer.cpp | 2 - tests/cefclient/osrplugin_test.cpp | 7 +- tests/cefclient/res/osrplugin.html | 3 +- tests/cefclient/res/osrtest.html | 1 + 14 files changed, 254 insertions(+), 341 deletions(-) diff --git a/libcef/browser_impl.cc b/libcef/browser_impl.cc index e69170f37..90780d1cf 100644 --- a/libcef/browser_impl.cc +++ b/libcef/browser_impl.cc @@ -1055,10 +1055,6 @@ void CefBrowserImpl::UIT_Invalidate(const CefRect& dirtyRect) { gfx::Rect rect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); - // Used when window rendering is disabled to send the specified region to - // the paint delegate when WebWidget::Paint() is next called. - host->UpdateRedrawRect(rect); - // Cause WebWidget::Paint() to be called when next appropriate. host->InvalidateRect(rect); } diff --git a/libcef/browser_webview_delegate.cc b/libcef/browser_webview_delegate.cc index c5c6d1a34..f03214684 100644 --- a/libcef/browser_webview_delegate.cc +++ b/libcef/browser_webview_delegate.cc @@ -509,13 +509,13 @@ WebCookieJar* BrowserWebViewDelegate::GetCookieJar() { void BrowserWebViewDelegate::didInvalidateRect(const WebRect& rect) { if (WebWidgetHost* host = GetWidgetHost()) - host->DidInvalidateRect(rect); + host->InvalidateRect(rect); } void BrowserWebViewDelegate::didScrollRect(int dx, int dy, const WebRect& clip_rect) { if (WebWidgetHost* host = GetWidgetHost()) - host->DidScrollRect(dx, dy, clip_rect); + host->ScrollRect(dx, dy, clip_rect); } void BrowserWebViewDelegate::scheduleComposite() { diff --git a/libcef/browser_webview_mac.mm b/libcef/browser_webview_mac.mm index ec087e81b..f60368f33 100644 --- a/libcef/browser_webview_mac.mm +++ b/libcef/browser_webview_mac.mm @@ -321,7 +321,8 @@ void ExtractUnderlines( [super setFrame:frameRect]; if (browser_ && browser_->UIT_GetWebView()) { const NSRect bounds = [self bounds]; - browser_->UIT_GetWebViewHost()->Resize(gfx::Rect(NSRectToCGRect(bounds))); + browser_->UIT_GetWebViewHost()->SetSize(bounds.size.width, + bounds.size.height); } } diff --git a/libcef/webview_host.cc b/libcef/webview_host.cc index a448ed907..fe959e578 100644 --- a/libcef/webview_host.cc +++ b/libcef/webview_host.cc @@ -3,6 +3,7 @@ // can be found in the LICENSE file. #include "libcef/webview_host.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" WebViewHost::WebViewHost(BrowserWebViewDelegate* delegate) : delegate_(delegate) { @@ -12,3 +13,7 @@ WebViewHost::WebViewHost(BrowserWebViewDelegate* delegate) WebViewHost::~WebViewHost() { } #endif + +bool WebViewHost::IsTransparent() { + return static_cast(webwidget_)->isTransparent(); +} diff --git a/libcef/webview_host.h b/libcef/webview_host.h index 61069c70b..793bf02d7 100644 --- a/libcef/webview_host.h +++ b/libcef/webview_host.h @@ -58,6 +58,8 @@ class WebViewHost : public WebWidgetHost { virtual void SetFocus(bool enable); #endif + virtual bool IsTransparent(); + protected: explicit WebViewHost(BrowserWebViewDelegate* delegate); diff --git a/libcef/webwidget_host.cc b/libcef/webwidget_host.cc index 28cd276ba..5705f524c 100644 --- a/libcef/webwidget_host.cc +++ b/libcef/webwidget_host.cc @@ -10,6 +10,7 @@ #include "base/message_loop.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h" +#include "webkit/glue/webkit_glue.h" using webkit::npapi::WebPluginGeometry; using WebKit::WebSize; @@ -17,38 +18,67 @@ using WebKit::WebSize; const int WebWidgetHost::kDefaultFrameRate = 30; const int WebWidgetHost::kMaxFrameRate = 90; -void WebWidgetHost::ScheduleComposite() { - ScheduleInvalidateTimer(); -} - -void WebWidgetHost::ScheduleAnimation() { - ScheduleInvalidateTimer(); -} - -void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) { -#if defined(OS_WIN) || defined(OS_MACOSX) - paint_rgn_.op(rect.x(), rect.y(), rect.right(), rect.bottom(), - SkRegion::kUnion_Op); -#else - // TODO(cef): Update all ports to use regions instead of rectangles. - paint_rect_ = paint_rect_.Union(rect); -#endif -} - -void WebWidgetHost::UpdateRedrawRect(const gfx::Rect& rect) { - if (!view_) - redraw_rect_ = redraw_rect_.Union(rect); -} - void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) { if (rect.IsEmpty()) return; - DidInvalidateRect(rect); + + int width, height; + GetSize(width, height); + const gfx::Rect client_rect(width, height); + + const gfx::Rect rect_in_client = client_rect.Intersect(rect); + if (rect_in_client.IsEmpty()) + return; + + UpdatePaintRect(rect_in_client); + + if (view_) + InvalidateWindowRect(rect_in_client); + else + ScheduleTimer(); +} + +void WebWidgetHost::ScheduleComposite() { + ScheduleTimer(); +} + +void WebWidgetHost::ScheduleAnimation() { + ScheduleTimer(); +} + +bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) { + if (!canvas_.get()) + return false; + + const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false); + DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); + + if (width == canvas_->getDevice()->width() && + height == canvas_->getDevice()->height()) { + // The specified width and height values are the same as the canvas size. + // Return the existing canvas contents. + const void* pixels = bitmap.getPixels(); + memcpy(rgba_buffer, pixels, width * height * 4); + return true; + } + + // Create a new canvas of the requested size. + scoped_ptr new_canvas( + new skia::PlatformCanvas(width, height, true)); + + new_canvas->writePixels(bitmap, 0, 0); + const SkBitmap& new_bitmap = new_canvas->getDevice()->accessBitmap(false); + DCHECK(new_bitmap.config() == SkBitmap::kARGB_8888_Config); + + // Return the new canvas contents. + const void* pixels = new_bitmap.getPixels(); + memcpy(rgba_buffer, pixels, width * height * 4); + return true; } void WebWidgetHost::SetSize(int width, int height) { webwidget_->resize(WebSize(width, height)); - DidInvalidateRect(gfx::Rect(0, 0, width, height)); + InvalidateRect(gfx::Rect(0, 0, width, height)); EnsureTooltip(); } @@ -104,61 +134,94 @@ void WebWidgetHost::SetFrameRate(int frames_per_second) { frame_delay_ = 1000 / frames_per_second; } -void WebWidgetHost::ScheduleInvalidateTimer() { - // Invalidation is only required when window rendering is enabled. - if (!view_ || invalidate_timer_.IsRunning()) - return; - - // Maintain the desired rate. - base::TimeDelta delta = base::TimeTicks::Now() - last_invalidate_time_; - int64 actualRate = delta.InMilliseconds(); - if (actualRate >= frame_delay_) - delta = base::TimeDelta::FromMilliseconds(1); - else - delta = base::TimeDelta::FromMilliseconds(frame_delay_ - actualRate); - - invalidate_timer_.Start( - FROM_HERE, - delta, - this, - &WebWidgetHost::DoInvalidate); -} - -void WebWidgetHost::DoInvalidate() { - if (!webwidget_) - return; - WebSize size = webwidget_->size(); - InvalidateRect(gfx::Rect(0, 0, size.width, size.height)); - - last_invalidate_time_ = base::TimeTicks::Now(); -} - -void WebWidgetHost::SchedulePaintTimer() { - if (layouting_ || paint_timer_.IsRunning()) - return; - - // Maintain the desired rate. - base::TimeDelta delta = base::TimeTicks::Now() - last_paint_time_; - int64 actualRate = delta.InMilliseconds(); - if (actualRate >= frame_delay_) - delta = base::TimeDelta::FromMilliseconds(1); - else - delta = base::TimeDelta::FromMilliseconds(frame_delay_ - actualRate); - - paint_timer_.Start( - FROM_HERE, - delta, - this, - &WebWidgetHost::DoPaint); -} - -void WebWidgetHost::DoPaint() { -#if defined(OS_MACOSX) - SkRegion region; - Paint(region); +void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) { +#if defined(OS_WIN) || defined(OS_MACOSX) + paint_rgn_.op(rect.x(), rect.y(), rect.right(), rect.bottom(), + SkRegion::kUnion_Op); #else - Paint(); + // TODO(cef): Update all ports to use regions instead of rectangles. + paint_rect_ = paint_rect_.Union(rect); #endif - - last_paint_time_ = base::TimeTicks::Now(); +} + +void WebWidgetHost::PaintRect(const gfx::Rect& rect) { +#ifndef NDEBUG + DCHECK(!painting_); +#endif + DCHECK(canvas_.get()); + + if (rect.IsEmpty()) + return; + + if (IsTransparent()) { + // When using transparency mode clear the rectangle before painting. + SkPaint clearpaint; + clearpaint.setARGB(0, 0, 0, 0); + clearpaint.setXfermodeMode(SkXfermode::kClear_Mode); + + SkRect skrc; + skrc.set(rect.x(), rect.y(), rect.right(), rect.bottom()); + canvas_->drawRect(skrc, clearpaint); + } + + set_painting(true); + webwidget_->paint(webkit_glue::ToWebCanvas(canvas_.get()), rect); + set_painting(false); +} + +void WebWidgetHost::ScheduleTimer() { + if (timer_.IsRunning()) + return; + + // This method may be called multiple times while the timer callback is + // executing. If so re-execute this method a single time after the callback + // has completed. + if (timer_executing_) { + if (!timer_wanted_) + timer_wanted_ = true; + return; + } + + // Maintain the desired rate. + base::TimeDelta delta = base::TimeTicks::Now() - timer_last_; + int64 actualRate = delta.InMilliseconds(); + if (actualRate >= frame_delay_) + delta = base::TimeDelta::FromMilliseconds(1); + else + delta = base::TimeDelta::FromMilliseconds(frame_delay_ - actualRate); + + timer_.Start( + FROM_HERE, + delta, + this, + &WebWidgetHost::DoTimer); +} + +void WebWidgetHost::DoTimer() { + timer_executing_ = true; + + if (view_) { + // Window rendering is enabled and we've received a requestAnimationFrame + // or similar call. Trigger the OS to invalidate/repaint the client area at + // the requested frequency. + InvalidateWindow(); + } else { + // Window rendering is disabled. Generate OnPaint() calls at the requested + // frequency. +#if defined(OS_MACOSX) + SkRegion region; + Paint(region); +#else + Paint(); +#endif + } + + timer_executing_ = false; + + timer_last_ = base::TimeTicks::Now(); + + if (timer_wanted_) { + timer_wanted_ = false; + ScheduleTimer(); + } } diff --git a/libcef/webwidget_host.h b/libcef/webwidget_host.h index 21f8acb02..74b3633fd 100644 --- a/libcef/webwidget_host.h +++ b/libcef/webwidget_host.h @@ -76,8 +76,9 @@ class WebWidgetHost { gfx::NativeView view_handle() const { return view_; } WebKit::WebWidget* webwidget() const { return webwidget_; } - void DidInvalidateRect(const gfx::Rect& rect); - void DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect); + void InvalidateRect(const gfx::Rect& rect); + + void ScrollRect(int dx, int dy, const gfx::Rect& clip_rect); // Called for accelerated content like WebGL. void ScheduleComposite(); @@ -89,20 +90,11 @@ class WebWidgetHost { void SetCursor(HCURSOR cursor); #endif - // Update the region that will be painted to the canvas by WebKit the next - // time that Paint() is called. - void UpdatePaintRect(const gfx::Rect& rect); - - // Update the region that will be drawn to the device the next time Paint() - // is called. This is only used when window rendering is disabled. - void UpdateRedrawRect(const gfx::Rect& rect); - #if defined(OS_MACOSX) void Paint(SkRegion& update_rgn); #else void Paint(); #endif - void InvalidateRect(const gfx::Rect& rect); bool GetImage(int width, int height, void* buffer); @@ -115,8 +107,6 @@ class WebWidgetHost { WebKit::WebKeyboardEvent GetLastKeyEvent() const { return last_key_event_; } - void PaintRect(const gfx::Rect& rect); - void SetTooltipText(const CefString& tooltip_text); void SendKeyEvent(cef_key_type_t type, const cef_key_info_t& keyInfo, @@ -137,6 +127,8 @@ class WebWidgetHost { void SetFrameRate(int frames_per_second); + virtual bool IsTransparent() { return false; } + void set_popup(bool popup) { popup_ = popup; } bool popup() { return popup_; } @@ -145,20 +137,26 @@ class WebWidgetHost { protected: WebWidgetHost(); - // Called from the Schedule*() methods. - void ScheduleInvalidateTimer(); - void DoInvalidate(); + // Update the region that will be painted to the canvas by WebKit the next + // time that Paint() is called. + void UpdatePaintRect(const gfx::Rect& rect); - // If window rendering is disabled paint messages are generated after all - // other pending messages have been processed. - void SchedulePaintTimer(); - void DoPaint(); + void PaintRect(const gfx::Rect& rect); + + // Trigger the OS to invalidate/repaint the window. + void InvalidateWindow(); + void InvalidateWindowRect(const gfx::Rect& rect); + + // When window rendering is enabled this method invalidates the client area to + // trigger repaint via the OS. When window rendering is disabled this method + // is used to generate CefRenderHandler::OnPaint() calls. + void ScheduleTimer(); + void DoTimer(); #if defined(OS_WIN) // Per-class wndproc. Returns true if the event should be swallowed. virtual bool WndProc(UINT message, WPARAM wparam, LPARAM lparam); - void Resize(LPARAM lparam); virtual void MouseEvent(UINT message, WPARAM wparam, LPARAM lparam); void WheelEvent(WPARAM wparam, LPARAM lparam); virtual void KeyEvent(UINT message, WPARAM wparam, LPARAM lparam); @@ -181,7 +179,6 @@ class WebWidgetHost { #elif defined(OS_MACOSX) // These need to be called from a non-subclass, so they need to be public. public: - void Resize(const gfx::Rect& rect); virtual void MouseEvent(NSEvent* event); void WheelEvent(NSEvent* event); virtual void KeyEvent(NSEvent* event); @@ -202,7 +199,6 @@ class WebWidgetHost { // --------------------------------------------------------------------------- static gfx::NativeView CreateWidget(gfx::NativeView parent_view, WebWidgetHost* host); - void Resize(const gfx::Size& size); virtual void KeyEvent(GdkEventKey* event); #endif @@ -239,14 +235,10 @@ class WebWidgetHost { gfx::Rect paint_rect_; #endif - // Used to coalesce DidInvalidateRect() events into a single DoPaint() call. - // Used when window rendering is disabled. - base::OneShotTimer paint_timer_; - base::TimeTicks last_paint_time_; - - // Used to coalesce Schedule*() events into a single Invalidate() call. - base::OneShotTimer invalidate_timer_; - base::TimeTicks last_invalidate_time_; + base::OneShotTimer timer_; + base::TimeTicks timer_last_; + bool timer_executing_; + bool timer_wanted_; int64 frame_delay_; @@ -255,9 +247,6 @@ class WebWidgetHost { base::RepeatingTimer ime_timer_; #endif - // Redraw rectangle requested by an explicit call to CefBrowser::Invalidate(). - gfx::Rect redraw_rect_; - // The map of windowed plugins that need to be drawn when window rendering is // disabled. typedef std::map @@ -289,12 +278,6 @@ class WebWidgetHost { WebKit::WebMouseEvent::Button mouse_button_down_; #endif -#if defined(TOOLKIT_GTK) - // Since GtkWindow resize is asynchronous, we have to stash the dimensions, - // so that the backing store doesn't have to wait for sizing to take place. - gfx::Size logical_size_; -#endif - WebKit::WebKeyboardEvent last_key_event_; bool painting_; diff --git a/libcef/webwidget_host_gtk.cc b/libcef/webwidget_host_gtk.cc index 7e50a3f8a..d010ed7ef 100644 --- a/libcef/webwidget_host_gtk.cc +++ b/libcef/webwidget_host_gtk.cc @@ -128,14 +128,14 @@ class WebWidgetHostGtkWidget { static void HandleSizeAllocate(GtkWidget* widget, GtkAllocation* allocation, WebWidgetHost* host) { - host->Resize(WebSize(allocation->width, allocation->height)); + host->SetSize(allocation->width, allocation->height); } // Size, position, or stacking of the GdkWindow changed. static gboolean HandleConfigure(GtkWidget* widget, GdkEventConfigure* config, WebWidgetHost* host) { - host->Resize(WebSize(config->width, config->height)); + host->SetSize(config->width, config->height); return FALSE; } @@ -146,7 +146,7 @@ class WebWidgetHostGtkWidget { // See comments above about what g_handling_expose is for. g_handling_expose = true; gfx::Rect rect(expose->area); - host->UpdatePaintRect(rect); + host->InvalidateRect(rect); host->Paint(); g_handling_expose = false; return FALSE; @@ -273,21 +273,10 @@ WebWidgetHost* WebWidgetHost::Create(GtkWidget* parent_view, return host; } -void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { - DLOG_IF(WARNING, painting_) << "unexpected invalidation while painting"; - - UpdatePaintRect(damaged_rect); - - if (!g_handling_expose) { - gtk_widget_queue_draw_area(GTK_WIDGET(view_), damaged_rect.x(), - damaged_rect.y(), damaged_rect.width(), damaged_rect.height()); - } -} - -void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { +void WebWidgetHost::ScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { // This is used for optimizing painting when the renderer is scrolled. We're // currently not doing any optimizations so just invalidate the region. - DidInvalidateRect(clip_rect); + InvalidateRect(clip_rect); } WebWidgetHost::WebWidgetHost() @@ -297,6 +286,8 @@ WebWidgetHost::WebWidgetHost() canvas_w_(0), canvas_h_(0), popup_(false), + timer_executing_(false), + timer_wanted_(false), frame_delay_(1000 / kDefaultFrameRate) { set_painting(false); } @@ -311,14 +302,24 @@ WebWidgetHost::~WebWidgetHost() { // webwidget_->close(); } -void WebWidgetHost::Resize(const gfx::Size &newsize) { - logical_size_ = newsize; - SetSize(newsize.width(), newsize.height()); +void WebWidgetHost::InvalidateWindow() { + int width, height; + GetSize(width, height); + const gfx::Rect client_rect(width, height); + InvalidateWindowRect(client_rect); +} + +void WebWidgetHost::InvalidateWindowRect(const gfx::Rect& rect) { + DCHECK(view_); + if (!g_handling_expose) { + gtk_widget_queue_draw_area(GTK_WIDGET(view_), rect.x(), + rect.y(), rect.width(), rect.height()); + } } void WebWidgetHost::Paint() { - int width = logical_size_.width(); - int height = logical_size_.height(); + int width, height; + GetSize(width, height); gfx::Rect client_rect(width, height); // Number of pixels that the canvas is allowed to differ from the client area. @@ -394,27 +395,12 @@ void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) { // TODO(port): Implement this method as part of tooltip support. } -bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) { - if (!canvas_.get()) - return false; - - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); - return false; -} - WebScreenInfo WebWidgetHost::GetScreenInfo() { Display* display = GtkWidgetGetDisplay(view_); int screen_num = GtkWidgetGetScreenNum(view_); return WebScreenInfoFactory::screenInfo(display, screen_num); } -void WebWidgetHost::PaintRect(const gfx::Rect& rect) { - set_painting(true); - webwidget_->paint(canvas_.get(), rect); - set_painting(false); -} - void WebWidgetHost::SendKeyEvent(cef_key_type_t type, const cef_key_info_t& keyInfo, int modifiers) { diff --git a/libcef/webwidget_host_mac.mm b/libcef/webwidget_host_mac.mm index a7e58722e..34271ed29 100644 --- a/libcef/webwidget_host_mac.mm +++ b/libcef/webwidget_host_mac.mm @@ -22,12 +22,10 @@ MSVC_POP_WARNING(); #import "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" #import "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h" #import "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" -#import "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #import "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" #import "third_party/skia/include/core/SkRegion.h" #import "ui/gfx/rect.h" #import "ui/gfx/size.h" -#import "webkit/glue/webkit_glue.h" using webkit::npapi::WebPluginGeometry; using WebKit::WebInputEvent; @@ -82,6 +80,8 @@ WebWidgetHost::WebWidgetHost() canvas_w_(0), canvas_h_(0), popup_(false), + timer_executing_(false), + timer_wanted_(false), frame_delay_(1000 / kDefaultFrameRate), mouse_modifiers_(0), painting_(false), @@ -92,27 +92,7 @@ WebWidgetHost::WebWidgetHost() WebWidgetHost::~WebWidgetHost() { } -void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { - int width, height; - GetSize(width, height); - const gfx::Rect client_rect(width, height); - - const gfx::Rect damaged_rect_in_client = client_rect.Intersect(damaged_rect); - if (damaged_rect_in_client.IsEmpty()) - return; - - UpdatePaintRect(damaged_rect_in_client); - - if (view_) { - NSRect cocoa_rect = NSRectFromCGRect(damaged_rect_in_client.ToCGRect()); - cocoa_rect.origin.y = client_rect.height() - NSMaxY(cocoa_rect); - [view_ setNeedsDisplayInRect:cocoa_rect]; - } else { - SchedulePaintTimer(); - } -} - -void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { +void WebWidgetHost::ScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { DCHECK(dx || dy); int width, height; @@ -137,7 +117,7 @@ void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { // of the view means we can just invalidate the entire scroll rect. if (!view_ || [view_ canDraw] || painting_ || layouting_ || Dx >= w || Dy >= h) { - DidInvalidateRect(clip_rect); + InvalidateRect(clip_rect); return; } @@ -161,7 +141,7 @@ void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { // to the screen buffer. rect = gfx::Rect(dx>=0? x: r - Dx, dy>=0? y: b - Dy, dx>0? Dx: w, dy>0? Dy: h); - DidInvalidateRect(rect); + InvalidateRect(rect); // If any part of the scrolled rect was marked as dirty make sure to redraw // it in the new scrolled-to location. Otherwise we can end up with artifacts @@ -170,7 +150,7 @@ void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { SkRegion moved_paint_rgn(paint_rgn_); moved_paint_rgn.translate(dx, dy); moved_paint_rgn.op(convertToSkiaRect(client_rect), SkRegion::kIntersect_Op); - DidInvalidateRect(convertFromSkiaRect(moved_paint_rgn.getBounds())); + InvalidateRect(convertFromSkiaRect(moved_paint_rgn.getBounds())); } void WebWidgetHost::Paint(SkRegion& update_rgn) { @@ -179,12 +159,6 @@ void WebWidgetHost::Paint(SkRegion& update_rgn) { gfx::Rect client_rect(width, height); SkRegion damaged_rgn; - if (!view_ && !redraw_rect_.IsEmpty()) { - // At a minimum we need to send the delegate the rectangle that was - // requested by calling CefBrowser::InvalidateRect(). - damaged_rgn.setRect(convertToSkiaRect(redraw_rect_)); - redraw_rect_ = gfx::Rect(); - } if (view_) { // Union the rectangle that WebKit think needs repainting with the rectangle @@ -325,44 +299,10 @@ void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) { // TODO(port): Implement this method as part of tooltip support. } -bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) { - if (!canvas_.get()) - return false; - - const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false); - DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); - - if (width == canvas_->getDevice()->width() && - height == canvas_->getDevice()->height()) { - // The specified width and height values are the same as the canvas size. - // Return the existing canvas contents. - const void* pixels = bitmap.getPixels(); - memcpy(rgba_buffer, pixels, width * height * 4); - return true; - } - - // Create a new canvas of the requested size. - scoped_ptr new_canvas( - new skia::PlatformCanvas(width, height, true)); - - new_canvas->writePixels(bitmap, 0, 0); - const SkBitmap& new_bitmap = new_canvas->getDevice()->accessBitmap(false); - DCHECK(new_bitmap.config() == SkBitmap::kARGB_8888_Config); - - // Return the new canvas contents. - const void* pixels = new_bitmap.getPixels(); - memcpy(rgba_buffer, pixels, width * height * 4); - return true; -} - WebScreenInfo WebWidgetHost::GetScreenInfo() { return WebScreenInfoFactory::screenInfo(view_); } -void WebWidgetHost::Resize(const gfx::Rect& rect) { - SetSize(rect.width(), rect.height()); -} - void WebWidgetHost::MouseEvent(NSEvent *event) { const WebMouseEvent& web_event = WebInputEventFactory::mouseEvent( event, view_); @@ -421,31 +361,6 @@ void WebWidgetHost::SetFocus(bool enable) { webwidget_->setFocus(enable); } -void WebWidgetHost::PaintRect(const gfx::Rect& rect) { -#ifndef NDEBUG - DCHECK(!painting_); -#endif - DCHECK(canvas_.get()); - - if (rect.IsEmpty()) - return; - - if (!popup() && ((WebKit::WebView*)webwidget_)->isTransparent()) { - // When using transparency mode clear the rectangle before painting. - SkPaint clearpaint; - clearpaint.setARGB(0, 0, 0, 0); - clearpaint.setXfermodeMode(SkXfermode::kClear_Mode); - - SkRect skrc; - skrc.set(rect.x(), rect.y(), rect.right(), rect.bottom()); - canvas_->drawRect(skrc, clearpaint); - } - - set_painting(true); - webwidget_->paint(webkit_glue::ToWebCanvas(canvas_.get()), rect); - set_painting(false); -} - void WebWidgetHost::SendKeyEvent(cef_key_type_t type, const cef_key_info_t& keyInfo, int modifiers) { @@ -636,6 +551,23 @@ void WebWidgetHost::SendFocusEvent(bool setFocus) { void WebWidgetHost::SendCaptureLostEvent() { } +void WebWidgetHost::InvalidateWindow() { + DCHECK(view_); + [view_ setNeedsDisplay:YES]; +} + +void WebWidgetHost::InvalidateWindowRect(const gfx::Rect& rect) { + DCHECK(view_); + + int width, height; + GetSize(width, height); + const gfx::Rect client_rect(width, height); + + NSRect cocoa_rect = NSRectFromCGRect(rect.ToCGRect()); + cocoa_rect.origin.y = client_rect.height() - NSMaxY(cocoa_rect); + [view_ setNeedsDisplayInRect:cocoa_rect]; +} + void WebWidgetHost::EnsureTooltip() { // TODO(port): Implement this method as part of tooltip support. } diff --git a/libcef/webwidget_host_win.cc b/libcef/webwidget_host_win.cc index 9d8a0ff47..57125ec62 100644 --- a/libcef/webwidget_host_win.cc +++ b/libcef/webwidget_host_win.cc @@ -20,7 +20,6 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "third_party/WebKit/Source/WebKit/chromium/public/win/WebInputEventFactory.h" #include "third_party/WebKit/Source/WebKit/chromium/public/win/WebScreenInfoFactory.h" #include "third_party/skia/include/core/SkRegion.h" @@ -134,9 +133,12 @@ LRESULT CALLBACK WebWidgetHost::WndProc(HWND hwnd, UINT message, WPARAM wparam, // during painting. return 0; - case WM_SIZE: - host->Resize(lparam); + case WM_SIZE: { + int width = LOWORD(lparam); + int height = HIWORD(lparam); + host->SetSize(width, height); return 0; + } case WM_MOUSEMOVE: case WM_MOUSELEAVE: @@ -266,26 +268,7 @@ LRESULT CALLBACK WebWidgetHost::WndProc(HWND hwnd, UINT message, WPARAM wparam, return DefWindowProc(hwnd, message, wparam, lparam); } -void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { - int width, height; - GetSize(width, height); - const gfx::Rect client_rect(width, height); - - const gfx::Rect damaged_rect_in_client = client_rect.Intersect(damaged_rect); - if (damaged_rect_in_client.IsEmpty()) - return; - - UpdatePaintRect(damaged_rect_in_client); - - if (view_) { - RECT r = damaged_rect_in_client.ToRECT(); - ::InvalidateRect(view_, &r, FALSE); - } else { - SchedulePaintTimer(); - } -} - -void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { +void WebWidgetHost::ScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { DCHECK(dx || dy); // Invalidate and re-paint the entire scroll rect if: @@ -296,7 +279,7 @@ void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { if (!view_ || !canvas_.get() || layouting_ || painting_ || abs(dx) >= clip_rect.width() || abs(dy) >= clip_rect.height() || paint_rgn_.intersects(convertToSkiaRect(clip_rect))) { - DidInvalidateRect(clip_rect); + InvalidateRect(clip_rect); return; } @@ -330,6 +313,8 @@ WebWidgetHost::WebWidgetHost() canvas_w_(0), canvas_h_(0), popup_(false), + timer_executing_(false), + timer_wanted_(false), track_mouse_leave_(false), frame_delay_(1000 / kDefaultFrameRate), tooltip_view_(NULL), @@ -350,6 +335,20 @@ WebWidgetHost::~WebWidgetHost() { } } +void WebWidgetHost::InvalidateWindow() { + int width, height; + GetSize(width, height); + const gfx::Rect client_rect(width, height); + InvalidateWindowRect(client_rect); +} + +void WebWidgetHost::InvalidateWindowRect(const gfx::Rect& rect) { + DCHECK(view_); + + RECT r = rect.ToRECT(); + ::InvalidateRect(view_, &r, FALSE); +} + bool WebWidgetHost::WndProc(UINT message, WPARAM wparam, LPARAM lparam) { switch (message) { case WM_ACTIVATE: @@ -370,12 +369,6 @@ void WebWidgetHost::Paint() { // Damaged rectangle used for drawing when window rendering is disabled. SkRegion damaged_rgn; - if (!view_ && !redraw_rect_.IsEmpty()) { - // At a minimum we need to send the delegate the rectangle that was - // requested by calling CefBrowser::InvalidateRect(). - damaged_rgn.setRect(convertToSkiaRect(redraw_rect_)); - redraw_rect_ = gfx::Rect(); - } if (view_ && !webwidget_->isAcceleratedCompositingActive()) { // Number of pixels that the canvas is allowed to differ from the client @@ -524,41 +517,10 @@ void WebWidgetHost::Paint() { } } -bool WebWidgetHost::GetImage(int width, int height, void* buffer) { - const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false); - DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); - - if (width == canvas_->getDevice()->width() && - height == canvas_->getDevice()->height()) { - // The specified width and height values are the same as the canvas size. - // Return the existing canvas contents. - const void* pixels = bitmap.getPixels(); - memcpy(buffer, pixels, width * height * 4); - return true; - } - - // Create a new canvas of the requested size. - scoped_ptr new_canvas( - new skia::PlatformCanvas(width, height, true)); - - new_canvas->writePixels(bitmap, 0, 0); - const SkBitmap& new_bitmap = new_canvas->getDevice()->accessBitmap(false); - DCHECK(new_bitmap.config() == SkBitmap::kARGB_8888_Config); - - // Return the new canvas contents. - const void* pixels = new_bitmap.getPixels(); - memcpy(buffer, pixels, width * height * 4); - return true; -} - WebScreenInfo WebWidgetHost::GetScreenInfo() { return WebScreenInfoFactory::screenInfo(view_); } -void WebWidgetHost::Resize(LPARAM lparam) { - SetSize(LOWORD(lparam), HIWORD(lparam)); -} - void WebWidgetHost::MouseEvent(UINT message, WPARAM wparam, LPARAM lparam) { const WebMouseEvent& event = WebInputEventFactory::mouseEvent( view_, message, wparam, lparam); @@ -727,28 +689,6 @@ void WebWidgetHost::TrackMouseLeave(bool track) { TrackMouseEvent(&tme); } -void WebWidgetHost::PaintRect(const gfx::Rect& rect) { -#ifndef NDEBUG - DCHECK(!painting_); -#endif - DCHECK(canvas_.get()); - - if (!popup() && ((WebKit::WebView*)webwidget_)->isTransparent()) { - // When using transparency mode clear the rectangle before painting. - SkPaint clearpaint; - clearpaint.setARGB(0, 0, 0, 0); - clearpaint.setXfermodeMode(SkXfermode::kClear_Mode); - - SkRect skrc; - skrc.set(rect.x(), rect.y(), rect.right(), rect.bottom()); - canvas_->drawRect(skrc, clearpaint); - } - - set_painting(true); - webwidget_->paint(canvas_.get(), rect); - set_painting(false); -} - void WebWidgetHost::SendKeyEvent(cef_key_type_t type, const cef_key_info_t& keyInfo, int modifiers) { diff --git a/tests/cefclient/osrenderer.cpp b/tests/cefclient/osrenderer.cpp index 3ed57627b..3a414feb6 100644 --- a/tests/cefclient/osrenderer.cpp +++ b/tests/cefclient/osrenderer.cpp @@ -136,8 +136,6 @@ void ClientOSRenderer::Render() { // Disable alpha blending. glDisable(GL_BLEND); } - - glFlush(); } void ClientOSRenderer::OnPopupShow(CefRefPtr browser, diff --git a/tests/cefclient/osrplugin_test.cpp b/tests/cefclient/osrplugin_test.cpp index fa76e389d..94c885063 100644 --- a/tests/cefclient/osrplugin_test.cpp +++ b/tests/cefclient/osrplugin_test.cpp @@ -61,6 +61,10 @@ void RunOSRPluginTest(CefRefPtr browser, bool transparent) { // Transparency test. browser->GetMainFrame()->LoadURL( "http://tests/transparency"); + } else if(elementId == "testAnimation") { + // requestAnimationFrame test. + browser->GetMainFrame()->LoadURL( + "http://mrdoob.com/lab/javascript/requestanimationframe/"); } else if (elementId == "testWindowlessPlugin") { // Load flash, which is a windowless plugin. browser->GetMainFrame()->LoadURL( @@ -99,6 +103,7 @@ void RunOSRPluginTest(CefRefPtr browser, bool transparent) { RegisterClickListener(document, listener, "reload"); RegisterClickListener(document, listener, "go"); RegisterClickListener(document, listener, "testTransparency"); + RegisterClickListener(document, listener, "testAnimation"); RegisterClickListener(document, listener, "testWindowlessPlugin"); RegisterClickListener(document, listener, "viewSource"); } @@ -109,7 +114,7 @@ void RunOSRPluginTest(CefRefPtr browser, bool transparent) { // Center the window on the screen. int screenX = GetSystemMetrics(SM_CXFULLSCREEN); int screenY = GetSystemMetrics(SM_CYFULLSCREEN); - int width = 1000, height = 760; + int width = 1000, height = 780; int x = (screenX - width) / 2; int y = (screenY - height) / 2; diff --git a/tests/cefclient/res/osrplugin.html b/tests/cefclient/res/osrplugin.html index 0115ee7e6..5a5f2d3dd 100644 --- a/tests/cefclient/res/osrplugin.html +++ b/tests/cefclient/res/osrplugin.html @@ -25,12 +25,13 @@
  • Click and drag the view with the left mouse button while holding the shift key.
  • Enter a URL and click the "Go!" button to browse to a new Website.
  • Click here to test transparency.
  • +
  • Click here to test requestAnimationFrame.
  • Click here to test a windowless plugin.
  • - +
     
    diff --git a/tests/cefclient/res/osrtest.html b/tests/cefclient/res/osrtest.html index c3fdc2eee..cb52d4624 100644 --- a/tests/cefclient/res/osrtest.html +++ b/tests/cefclient/res/osrtest.html @@ -21,6 +21,7 @@
  • Click and drag the view with the left mouse button while holding the shift key.
  • Enter a URL and click the "Go!" button to browse to a new Website.
  • Click here to test transparency.
  • +
  • Click here to test requestAnimationFrame.
  • Click here to test a windowless plugin.