- Reduce CPU usage with requestAnimationFrame by maintaining a consistent 60fps frame rate (issue #456).

- (Win) Reduce memory/CPU usage with UpdateInputMethod by restricting tasks to every 100ms (issue #454).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@423 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2011-12-16 12:24:09 +00:00
parent 10b3b3cc41
commit 87507e875c
5 changed files with 98 additions and 44 deletions

View File

@ -14,10 +14,31 @@ using webkit::npapi::WebPluginGeometry;
using WebKit::WebSize;
void WebWidgetHost::ScheduleComposite() {
if (has_invalidate_task_)
return;
has_invalidate_task_ = true;
// Try to paint at 60fps.
static int64 kDesiredRate = 16;
base::TimeDelta delta = base::TimeTicks::Now() - paint_last_call_;
int64 actualRate = delta.InMilliseconds();
if (actualRate >= kDesiredRate) {
// Can't keep up so run as fast as possible.
MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(&WebWidgetHost::Invalidate, weak_factory_.GetWeakPtr()));
} else {
// Maintain the desired rate.
MessageLoop::current()->PostDelayedTask(FROM_HERE,
base::Bind(&WebWidgetHost::Invalidate, weak_factory_.GetWeakPtr()),
kDesiredRate - actualRate);
}
}
void WebWidgetHost::ScheduleAnimation() {
MessageLoop::current()->PostDelayedTask(FROM_HERE,
base::Bind(&WebWidgetHost::ScheduleComposite, weak_factory_.GetWeakPtr()),
10);
ScheduleComposite();
}
void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) {

View File

@ -12,6 +12,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task.h"
#include "base/time.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h"
@ -73,8 +74,17 @@ class WebWidgetHost {
void DidInvalidateRect(const gfx::Rect& rect);
void DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect);
// Called for accelerated content like WebGL.
void ScheduleComposite();
// Called for requestAnimationFrame animations.
void ScheduleAnimation();
// Invalidate the complete client area. This is called at a reasonable frame
// rate by the Schedule*() methods.
void Invalidate();
#if defined(OS_WIN)
void SetCursor(HCURSOR cursor);
#endif
@ -161,7 +171,7 @@ class WebWidgetHost {
void OnInputLangChange(DWORD character_set, HKL input_language_id);
void ImeUpdateTextInputState(WebKit::WebTextInputType type,
const gfx::Rect& caret_rect);
static void UpdateInputMethod(HWND view);
void UpdateInputMethod();
#elif defined(OS_MACOSX)
// These need to be called from a non-subclass, so they need to be public.
public:
@ -225,6 +235,17 @@ class WebWidgetHost {
// True if an update task is pending when window rendering is disabled.
bool has_update_task_;
// True if an invalidate task is pending due to the Schedule*() methods.
bool has_invalidate_task_;
#if defined(OS_WIN)
// True if an update input method task is pending due to DidInvalidateRect().
bool has_update_input_method_task_;
#endif
// When the Paint() method last completed.
base::TimeTicks paint_last_call_;
// Redraw rectangle requested by an explicit call to CefBrowser::Invalidate().
gfx::Rect redraw_rect_;

View File

@ -302,7 +302,7 @@ void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) {
DidInvalidateRect(clip_rect);
}
void WebWidgetHost::ScheduleComposite() {
void WebWidgetHost::Invalidate() {
int width = logical_size_.width();
int height = logical_size_.height();
GdkRectangle grect = {
@ -323,6 +323,7 @@ WebWidgetHost::WebWidgetHost()
canvas_h_(0),
popup_(false),
has_update_task_(false),
has_invalidate_task_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
set_painting(false);
}
@ -414,6 +415,11 @@ void WebWidgetHost::Paint() {
cairo_destroy(cairo_drawable);
gdk_window_end_paint(window);
// Used with scheduled invalidation to maintain a consistent frame rate.
paint_last_call_ = base::TimeTicks::Now();
if (has_invalidate_task_)
has_invalidate_task_ = false;
}
void WebWidgetHost::SetTooltipText(const CefString& tooltip_text)

View File

@ -67,6 +67,7 @@ WebWidgetHost::WebWidgetHost()
canvas_h_(0),
popup_(false),
has_update_task_(false),
has_invalidate_task_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
set_painting(false);
}
@ -177,12 +178,13 @@ void WebWidgetHost::Paint(SkRegion& update_rgn) {
paint_rgn_.setRect(convertToSkiaRect(client_rect));
}
// Animate the view and layout any views that have not been laid out yet. The
// latter may result in more invalidation. Keep track of the fact that we are
// laying out views, because this will sometimes cause ScrollRect to be called
// and we don't want to try to scrollRect:by: then.
layouting_ = true;
webwidget_->animate(0.0);
// Layout any views that have not been laid out yet. The layout may result in
// more invalidation. Keep track of the fact that we are laying out views,
// because this will sometimes cause ScrollRect to be called and we don't want
// to try to scrollRect:by: then.
layouting_ = true;
webwidget_->layout();
layouting_ = false;
@ -225,9 +227,14 @@ void WebWidgetHost::Paint(SkRegion& update_rgn) {
const float y = client_rect.height() - r.bottom();
skia::DrawToNativeContext(canvas_.get(), context, x, y, &copy_rect);
}
// Used with scheduled invalidation to maintain a consistent frame rate.
paint_last_call_ = base::TimeTicks::Now();
if (has_invalidate_task_)
has_invalidate_task_ = false;
}
void WebWidgetHost::ScheduleComposite() {
void WebWidgetHost::Invalidate() {
[view_ setNeedsDisplay:YES];
}

View File

@ -273,9 +273,15 @@ void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) {
UpdatePaintRect(damaged_rect);
InvalidateRect(damaged_rect);
if (!popup_ && view_) {
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableFunction(
&WebWidgetHost::UpdateInputMethod, view_));
if (!popup_ && view_ && webwidget_ && input_method_is_active_ &&
!has_update_input_method_task_) {
has_update_input_method_task_ = true;
// Call UpdateInputMethod() approximately every 100ms.
CefThread::PostDelayedTask(CefThread::UI, FROM_HERE,
base::Bind(&WebWidgetHost::UpdateInputMethod,
weak_factory_.GetWeakPtr()),
100);
}
}
@ -308,7 +314,7 @@ void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) {
InvalidateRect(clip_rect);
}
void WebWidgetHost::ScheduleComposite() {
void WebWidgetHost::Invalidate() {
if (!webwidget_)
return;
WebSize size = webwidget_->size();
@ -331,6 +337,8 @@ WebWidgetHost::WebWidgetHost()
popup_(false),
track_mouse_leave_(false),
has_update_task_(false),
has_invalidate_task_(false),
has_update_input_method_task_(false),
tooltip_view_(NULL),
tooltip_showing_(false),
ime_notification_(false),
@ -403,12 +411,11 @@ void WebWidgetHost::Paint() {
canvas_.reset(new skia::PlatformCanvas(canvas_w_, canvas_h_, true));
}
layouting_ = true;
webwidget_->animate(0.0);
// This may result in more invalidation.
layouting_ = true;
webwidget_->layout();
layouting_ = false;
// Paint the canvas if necessary. Allow painting to generate extra rects the
@ -519,6 +526,11 @@ void WebWidgetHost::Paint() {
paint_delegate_->Paint(popup_, damaged_rects, pixels);
}
// Used with scheduled invalidation to maintain a consistent frame rate.
paint_last_call_ = base::TimeTicks::Now();
if (has_invalidate_task_)
has_invalidate_task_ = false;
}
void WebWidgetHost::InvalidateRect(const gfx::Rect& rect)
@ -1091,40 +1103,27 @@ void WebWidgetHost::ImeUpdateTextInputState(WebKit::WebTextInputType type,
ime_input_.UpdateCaretRect(view_, caret_rect);
}
/* static */
void WebWidgetHost::UpdateInputMethod(HWND view)
void WebWidgetHost::UpdateInputMethod()
{
// Since we call this function asynchronously (via PostTask), we
// must ensure that we haven't destroyed the window by the time this
// function executes
if (!::IsWindow(view))
REQUIRE_UIT();
has_update_input_method_task_ = false;
if (!input_method_is_active_ || !webwidget_)
return;
WebWidgetHost* host = FromWindow(view);
if (!host || !host->input_method_is_active_)
return;
if (!host->webwidget_ || !CefThread::CurrentlyOn(CefThread::UI))
return;
WebKit::WebTextInputType new_type = WebKit::WebTextInputTypeNone;
WebKit::WebTextInputType new_type = webwidget_->textInputType();
WebKit::WebRect new_caret_bounds;
if (host->webwidget_) {
new_type = host->webwidget_->textInputType();
WebKit::WebRect startRect, endRect;
if (host->webwidget_->selectionBounds(startRect, endRect))
new_caret_bounds = endRect;
}
WebKit::WebRect startRect, endRect;
if (webwidget_->selectionBounds(startRect, endRect))
new_caret_bounds = endRect;
// Only sends text input type and caret bounds to the browser process if they
// are changed.
if (host->text_input_type_ != new_type ||
host->caret_bounds_ != new_caret_bounds) {
host->text_input_type_ = new_type;
host->caret_bounds_ = new_caret_bounds;
host->ImeUpdateTextInputState(new_type, new_caret_bounds);
if (text_input_type_ != new_type || caret_bounds_ != new_caret_bounds) {
text_input_type_ = new_type;
caret_bounds_ = new_caret_bounds;
ImeUpdateTextInputState(new_type, new_caret_bounds);
}
}