mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Improve the handling of invalidation/painting for off-screen rendering (issue #695).
git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@737 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
#include "libcef/cef_thread.h"
|
#include "libcef/cef_thread.h"
|
||||||
|
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
|
#include "base/logging.h"
|
||||||
#include "base/message_loop.h"
|
#include "base/message_loop.h"
|
||||||
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
|
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
|
||||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h"
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h"
|
||||||
@@ -15,26 +16,18 @@ using WebKit::WebSize;
|
|||||||
|
|
||||||
|
|
||||||
void WebWidgetHost::ScheduleComposite() {
|
void WebWidgetHost::ScheduleComposite() {
|
||||||
if (has_invalidate_task_)
|
if (invalidate_timer_.IsRunning())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
has_invalidate_task_ = true;
|
|
||||||
|
|
||||||
// Try to paint at 60fps.
|
// Try to paint at 60fps.
|
||||||
static int64 kDesiredRate = 16;
|
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.
|
// Maintain the desired rate.
|
||||||
MessageLoop::current()->PostDelayedTask(FROM_HERE,
|
invalidate_timer_.Start(
|
||||||
base::Bind(&WebWidgetHost::Invalidate, weak_factory_.GetWeakPtr()),
|
FROM_HERE,
|
||||||
base::TimeDelta::FromMilliseconds(kDesiredRate - actualRate));
|
base::TimeDelta::FromMilliseconds(kDesiredRate),
|
||||||
}
|
this,
|
||||||
|
&WebWidgetHost::Invalidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebWidgetHost::ScheduleAnimation() {
|
void WebWidgetHost::ScheduleAnimation() {
|
||||||
@@ -105,9 +98,19 @@ gfx::PluginWindowHandle WebWidgetHost::GetWindowedPluginAt(int x, int y) {
|
|||||||
return gfx::kNullPluginWindow;
|
return gfx::kNullPluginWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebWidgetHost::SchedulePaintTimer() {
|
||||||
|
if (layouting_ || paint_timer_.IsRunning())
|
||||||
|
return;
|
||||||
|
|
||||||
|
paint_timer_.Start(
|
||||||
|
FROM_HERE,
|
||||||
|
base::TimeDelta::FromMilliseconds(0), // Fire immediately.
|
||||||
|
this,
|
||||||
|
&WebWidgetHost::DoPaint);
|
||||||
|
}
|
||||||
|
|
||||||
void WebWidgetHost::DoPaint() {
|
void WebWidgetHost::DoPaint() {
|
||||||
if (MessageLoop::current()->IsIdle()) {
|
if (MessageLoop::current()->IsIdle()) {
|
||||||
has_update_task_ = false;
|
|
||||||
// Paint to the delegate.
|
// Paint to the delegate.
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
SkRegion region;
|
SkRegion region;
|
||||||
@@ -117,7 +120,6 @@ void WebWidgetHost::DoPaint() {
|
|||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
// Try again later.
|
// Try again later.
|
||||||
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
SchedulePaintTimer();
|
||||||
base::Bind(&WebWidgetHost::DoPaint, weak_factory_.GetWeakPtr()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,8 +15,8 @@
|
|||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "base/memory/scoped_ptr.h"
|
#include "base/memory/scoped_ptr.h"
|
||||||
#include "base/memory/weak_ptr.h"
|
|
||||||
#include "base/time.h"
|
#include "base/time.h"
|
||||||
|
#include "base/timer.h"
|
||||||
#include "skia/ext/platform_canvas.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/WebInputEvent.h"
|
||||||
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
|
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
|
||||||
@@ -139,10 +139,6 @@ class WebWidgetHost {
|
|||||||
void MoveWindowedPlugin(const webkit::npapi::WebPluginGeometry& geometry);
|
void MoveWindowedPlugin(const webkit::npapi::WebPluginGeometry& geometry);
|
||||||
gfx::PluginWindowHandle GetWindowedPluginAt(int x, int y);
|
gfx::PluginWindowHandle GetWindowedPluginAt(int x, int y);
|
||||||
|
|
||||||
// If window rendering is disabled paint messages are generated after all
|
|
||||||
// other pending messages have been processed.
|
|
||||||
void DoPaint();
|
|
||||||
|
|
||||||
void set_popup(bool popup) { popup_ = popup; }
|
void set_popup(bool popup) { popup_ = popup; }
|
||||||
bool popup() { return popup_; }
|
bool popup() { return popup_; }
|
||||||
|
|
||||||
@@ -151,6 +147,11 @@ class WebWidgetHost {
|
|||||||
protected:
|
protected:
|
||||||
WebWidgetHost();
|
WebWidgetHost();
|
||||||
|
|
||||||
|
// If window rendering is disabled paint messages are generated after all
|
||||||
|
// other pending messages have been processed.
|
||||||
|
void SchedulePaintTimer();
|
||||||
|
void DoPaint();
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
// Per-class wndproc. Returns true if the event should be swallowed.
|
// Per-class wndproc. Returns true if the event should be swallowed.
|
||||||
virtual bool WndProc(UINT message, WPARAM wparam, LPARAM lparam);
|
virtual bool WndProc(UINT message, WPARAM wparam, LPARAM lparam);
|
||||||
@@ -173,9 +174,8 @@ class WebWidgetHost {
|
|||||||
LRESULT OnImeEndComposition(UINT message, WPARAM wparam, LPARAM lparam,
|
LRESULT OnImeEndComposition(UINT message, WPARAM wparam, LPARAM lparam,
|
||||||
BOOL& handled);
|
BOOL& handled);
|
||||||
void OnInputLangChange(DWORD character_set, HKL input_language_id);
|
void OnInputLangChange(DWORD character_set, HKL input_language_id);
|
||||||
void ImeUpdateTextInputState(WebKit::WebTextInputType type,
|
void UpdateImeInputState();
|
||||||
const gfx::Rect& caret_rect);
|
void ToggleImeTimer();
|
||||||
void UpdateInputMethod();
|
|
||||||
#elif defined(OS_MACOSX)
|
#elif defined(OS_MACOSX)
|
||||||
// These need to be called from a non-subclass, so they need to be public.
|
// These need to be called from a non-subclass, so they need to be public.
|
||||||
public:
|
public:
|
||||||
@@ -237,20 +237,18 @@ class WebWidgetHost {
|
|||||||
gfx::Rect paint_rect_;
|
gfx::Rect paint_rect_;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// True if an update task is pending when window rendering is disabled.
|
// Used to coalesce DidInvalidateRect() events into a single DoPaint() call.
|
||||||
bool has_update_task_;
|
// Used when window rendering is disabled.
|
||||||
|
base::OneShotTimer<WebWidgetHost> paint_timer_;
|
||||||
|
|
||||||
// True if an invalidate task is pending due to the Schedule*() methods.
|
// Used to coalesce Schedule*() events into a single Invalidate() call.
|
||||||
bool has_invalidate_task_;
|
base::OneShotTimer<WebWidgetHost> invalidate_timer_;
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
// True if an update input method task is pending due to DidInvalidateRect().
|
// Used to call UpdateImeInputState() while IME is active.
|
||||||
bool has_update_input_method_task_;
|
base::RepeatingTimer<WebWidgetHost> ime_timer_;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// When the Paint() method last completed.
|
|
||||||
base::TimeTicks paint_last_call_;
|
|
||||||
|
|
||||||
// Redraw rectangle requested by an explicit call to CefBrowser::Invalidate().
|
// Redraw rectangle requested by an explicit call to CefBrowser::Invalidate().
|
||||||
gfx::Rect redraw_rect_;
|
gfx::Rect redraw_rect_;
|
||||||
|
|
||||||
@@ -269,20 +267,16 @@ class WebWidgetHost {
|
|||||||
// Wrapper class for IME input.
|
// Wrapper class for IME input.
|
||||||
ui::ImeInput ime_input_;
|
ui::ImeInput ime_input_;
|
||||||
|
|
||||||
// Represents whether or not this browser process is receiving status
|
// Represents whether or not this browser process is receiving status messages
|
||||||
// messages about the focused edit control from a renderer process.
|
// about the focused edit control from a renderer process.
|
||||||
bool ime_notification_;
|
bool ime_notification_;
|
||||||
|
|
||||||
// Represents whether or not the IME of a browser process is active.
|
// Stores the current text input type.
|
||||||
bool input_method_is_active_;
|
|
||||||
|
|
||||||
// Stores the current text input type received by ImeUpdateTextInputState()
|
|
||||||
// method.
|
|
||||||
WebKit::WebTextInputType text_input_type_;
|
WebKit::WebTextInputType text_input_type_;
|
||||||
|
|
||||||
// Stores the current caret bounds of input focus.
|
// Stores the current caret bounds of input focus.
|
||||||
WebKit::WebRect caret_bounds_;
|
WebKit::WebRect caret_bounds_;
|
||||||
#endif
|
#endif // OS_WIN
|
||||||
|
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
int mouse_modifiers_;
|
int mouse_modifiers_;
|
||||||
@@ -299,9 +293,6 @@ class WebWidgetHost {
|
|||||||
|
|
||||||
bool painting_;
|
bool painting_;
|
||||||
bool layouting_;
|
bool layouting_;
|
||||||
|
|
||||||
private:
|
|
||||||
base::WeakPtrFactory<WebWidgetHost> weak_factory_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CEF_LIBCEF_WEBWIDGET_HOST_H_
|
#endif // CEF_LIBCEF_WEBWIDGET_HOST_H_
|
||||||
|
@@ -309,10 +309,7 @@ WebWidgetHost::WebWidgetHost()
|
|||||||
webwidget_(NULL),
|
webwidget_(NULL),
|
||||||
canvas_w_(0),
|
canvas_w_(0),
|
||||||
canvas_h_(0),
|
canvas_h_(0),
|
||||||
popup_(false),
|
popup_(false) {
|
||||||
has_update_task_(false),
|
|
||||||
has_invalidate_task_(false),
|
|
||||||
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
|
|
||||||
set_painting(false);
|
set_painting(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,11 +400,6 @@ void WebWidgetHost::Paint() {
|
|||||||
cairo_destroy(cairo_drawable);
|
cairo_destroy(cairo_drawable);
|
||||||
|
|
||||||
gdk_window_end_paint(window);
|
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) {
|
void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) {
|
||||||
|
@@ -22,7 +22,7 @@ MSVC_POP_WARNING();
|
|||||||
#import "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
|
#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/WebPopupMenu.h"
|
||||||
#import "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h"
|
#import "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h"
|
||||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.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/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
|
||||||
#import "third_party/skia/include/core/SkRegion.h"
|
#import "third_party/skia/include/core/SkRegion.h"
|
||||||
#import "ui/gfx/rect.h"
|
#import "ui/gfx/rect.h"
|
||||||
@@ -82,12 +82,9 @@ WebWidgetHost::WebWidgetHost()
|
|||||||
canvas_w_(0),
|
canvas_w_(0),
|
||||||
canvas_h_(0),
|
canvas_h_(0),
|
||||||
popup_(false),
|
popup_(false),
|
||||||
has_update_task_(false),
|
|
||||||
has_invalidate_task_(false),
|
|
||||||
mouse_modifiers_(0),
|
mouse_modifiers_(0),
|
||||||
painting_(false),
|
painting_(false),
|
||||||
layouting_(false),
|
layouting_(false) {
|
||||||
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
|
|
||||||
set_painting(false);
|
set_painting(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,8 +97,9 @@ void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) {
|
|||||||
const gfx::Rect client_rect(width, height);
|
const gfx::Rect client_rect(width, height);
|
||||||
|
|
||||||
const gfx::Rect damaged_rect_in_client = client_rect.Intersect(damaged_rect);
|
const gfx::Rect damaged_rect_in_client = client_rect.Intersect(damaged_rect);
|
||||||
|
if (damaged_rect_in_client.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
if (!damaged_rect_in_client.IsEmpty()) {
|
|
||||||
UpdatePaintRect(damaged_rect_in_client);
|
UpdatePaintRect(damaged_rect_in_client);
|
||||||
|
|
||||||
if (view_) {
|
if (view_) {
|
||||||
@@ -109,15 +107,7 @@ void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) {
|
|||||||
cocoa_rect.origin.y = client_rect.height() - NSMaxY(cocoa_rect);
|
cocoa_rect.origin.y = client_rect.height() - NSMaxY(cocoa_rect);
|
||||||
[view_ setNeedsDisplayInRect:cocoa_rect];
|
[view_ setNeedsDisplayInRect:cocoa_rect];
|
||||||
} else {
|
} else {
|
||||||
// Don't post a paint task if this invalidation occurred during layout or
|
SchedulePaintTimer();
|
||||||
// if a paint task is already pending. Paint() will be called by
|
|
||||||
// DoPaint().
|
|
||||||
if (!layouting_ && !has_update_task_) {
|
|
||||||
has_update_task_ = true;
|
|
||||||
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
|
||||||
base::Bind(&WebWidgetHost::DoPaint, weak_factory_.GetWeakPtr()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,6 +299,9 @@ void WebWidgetHost::Paint(SkRegion& update_rgn) {
|
|||||||
skia::DrawToNativeContext(canvas_.get(), context, x, y, ©_rect);
|
skia::DrawToNativeContext(canvas_.get(), context, x, y, ©_rect);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (damaged_rgn.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
// Paint to the delegate.
|
// Paint to the delegate.
|
||||||
DCHECK(paint_delegate_);
|
DCHECK(paint_delegate_);
|
||||||
const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false);
|
const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false);
|
||||||
@@ -325,20 +318,14 @@ void WebWidgetHost::Paint(SkRegion& update_rgn) {
|
|||||||
|
|
||||||
paint_delegate_->Paint(popup_, damaged_rects, pixels);
|
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::Invalidate() {
|
void WebWidgetHost::Invalidate() {
|
||||||
if (view_) {
|
if (!webwidget_)
|
||||||
[view_ setNeedsDisplay:YES];
|
return;
|
||||||
} else if (webwidget_) {
|
|
||||||
WebSize size = webwidget_->size();
|
WebSize size = webwidget_->size();
|
||||||
InvalidateRect(gfx::Rect(0, 0, size.width, size.height));
|
InvalidateRect(gfx::Rect(0, 0, size.width, size.height));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) {
|
void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) {
|
||||||
@@ -349,17 +336,7 @@ void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) {
|
|||||||
if (rect.IsEmpty())
|
if (rect.IsEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!view_) {
|
DidInvalidateRect(rect);
|
||||||
// Don't post a paint task if this invalidation occurred during layout or if
|
|
||||||
// a paint task is already pending. Paint() will be called by DoPaint().
|
|
||||||
if (!layouting_ && !has_update_task_) {
|
|
||||||
has_update_task_ = true;
|
|
||||||
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
|
||||||
base::Bind(&WebWidgetHost::DoPaint, weak_factory_.GetWeakPtr()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
NOTIMPLEMENTED();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) {
|
bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) {
|
||||||
|
@@ -102,7 +102,6 @@ WebWidgetHost* WebWidgetHost::Create(HWND parent_view,
|
|||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
parent_view, NULL, GetModuleHandle(NULL),
|
parent_view, NULL, GetModuleHandle(NULL),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
ui::SetWindowUserData(host->view_, host);
|
ui::SetWindowUserData(host->view_, host);
|
||||||
} else {
|
} else {
|
||||||
host->paint_delegate_ = paint_delegate;
|
host->paint_delegate_ = paint_delegate;
|
||||||
@@ -268,22 +267,21 @@ LRESULT CALLBACK WebWidgetHost::WndProc(HWND hwnd, UINT message, WPARAM wparam,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) {
|
void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) {
|
||||||
DLOG_IF(WARNING, painting_) << "unexpected invalidation while painting";
|
int width, height;
|
||||||
|
GetSize(width, height);
|
||||||
|
const gfx::Rect client_rect(width, height);
|
||||||
|
|
||||||
// If this invalidate overlaps with a pending scroll then we have to downgrade
|
const gfx::Rect damaged_rect_in_client = client_rect.Intersect(damaged_rect);
|
||||||
// to invalidating the scroll rect.
|
if (damaged_rect_in_client.IsEmpty())
|
||||||
UpdatePaintRect(damaged_rect);
|
return;
|
||||||
InvalidateRect(damaged_rect);
|
|
||||||
|
|
||||||
if (!popup_ && view_ && webwidget_ && input_method_is_active_ &&
|
UpdatePaintRect(damaged_rect_in_client);
|
||||||
!has_update_input_method_task_) {
|
|
||||||
has_update_input_method_task_ = true;
|
|
||||||
|
|
||||||
// Call UpdateInputMethod() approximately every 100ms.
|
if (view_) {
|
||||||
CefThread::PostDelayedTask(CefThread::UI, FROM_HERE,
|
RECT r = damaged_rect_in_client.ToRECT();
|
||||||
base::Bind(&WebWidgetHost::UpdateInputMethod,
|
::InvalidateRect(view_, &r, FALSE);
|
||||||
weak_factory_.GetWeakPtr()),
|
} else {
|
||||||
base::TimeDelta::FromMilliseconds(100));
|
SchedulePaintTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +312,8 @@ void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) {
|
|||||||
|
|
||||||
// Invalidate the scroll rect. It will be drawn from the canvas bitmap on the
|
// Invalidate the scroll rect. It will be drawn from the canvas bitmap on the
|
||||||
// next WM_PAINT call.
|
// next WM_PAINT call.
|
||||||
InvalidateRect(clip_rect);
|
RECT r = clip_rect.ToRECT();
|
||||||
|
::InvalidateRect(view_, &r, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebWidgetHost::Invalidate() {
|
void WebWidgetHost::Invalidate() {
|
||||||
@@ -339,16 +338,11 @@ WebWidgetHost::WebWidgetHost()
|
|||||||
canvas_h_(0),
|
canvas_h_(0),
|
||||||
popup_(false),
|
popup_(false),
|
||||||
track_mouse_leave_(false),
|
track_mouse_leave_(false),
|
||||||
has_update_task_(false),
|
|
||||||
has_invalidate_task_(false),
|
|
||||||
has_update_input_method_task_(false),
|
|
||||||
tooltip_view_(NULL),
|
tooltip_view_(NULL),
|
||||||
tooltip_showing_(false),
|
tooltip_showing_(false),
|
||||||
ime_notification_(false),
|
ime_notification_(false),
|
||||||
input_method_is_active_(false),
|
|
||||||
layouting_(false),
|
layouting_(false),
|
||||||
text_input_type_(WebKit::WebTextInputTypeNone),
|
text_input_type_(WebKit::WebTextInputTypeNone) {
|
||||||
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
|
|
||||||
set_painting(false);
|
set_painting(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,6 +509,9 @@ void WebWidgetHost::Paint() {
|
|||||||
// Draw children
|
// Draw children
|
||||||
UpdateWindow(view_);
|
UpdateWindow(view_);
|
||||||
} else {
|
} else {
|
||||||
|
if (damaged_rgn.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
// Paint to the delegate.
|
// Paint to the delegate.
|
||||||
DCHECK(paint_delegate_);
|
DCHECK(paint_delegate_);
|
||||||
const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false);
|
const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false);
|
||||||
@@ -531,30 +528,13 @@ void WebWidgetHost::Paint() {
|
|||||||
|
|
||||||
paint_delegate_->Paint(popup_, damaged_rects, pixels);
|
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) {
|
void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) {
|
||||||
if (rect.IsEmpty())
|
if (rect.IsEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (view_) {
|
DidInvalidateRect(rect);
|
||||||
// Let the window handle painting.
|
|
||||||
RECT r = rect.ToRECT();
|
|
||||||
::InvalidateRect(view_, &r, FALSE);
|
|
||||||
} else {
|
|
||||||
// Don't post a paint task if this invalidation occurred during layout or if
|
|
||||||
// a paint task is already pending. Paint() will be called by DoPaint().
|
|
||||||
if (!layouting_ && !has_update_task_) {
|
|
||||||
has_update_task_ = true;
|
|
||||||
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
|
||||||
base::Bind(&WebWidgetHost::DoPaint, weak_factory_.GetWeakPtr()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebWidgetHost::GetImage(int width, int height, void* buffer) {
|
bool WebWidgetHost::GetImage(int width, int height, void* buffer) {
|
||||||
@@ -947,26 +927,22 @@ LRESULT WebWidgetHost::OnImeSetContext(UINT message, WPARAM wparam,
|
|||||||
if (!webwidget_)
|
if (!webwidget_)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// We need status messages about the focused input control from a
|
// We need to start the IME timer when:
|
||||||
// renderer process when:
|
|
||||||
// * the current input context has IMEs, and;
|
// * the current input context has IMEs, and;
|
||||||
// * an application is activated.
|
// * an application is activated.
|
||||||
// This seems to tell we should also check if the current input context has
|
// This seems to indicate that we should also check if the current input
|
||||||
// IMEs before sending a request, however, this WM_IME_SETCONTEXT is
|
// context has IMEs before starting the timer, however, this WM_IME_SETCONTEXT
|
||||||
// fortunately sent to an application only while the input context has IMEs.
|
// is fortunately sent to an application only while the input context has
|
||||||
// Therefore, we just start/stop status messages according to the activation
|
// IMEs. Therefore, we just start/stop the timer according to the activation
|
||||||
// status of this application without checks.
|
// status of this application without checks.
|
||||||
bool activated = (wparam == TRUE);
|
ime_notification_ = (wparam == TRUE);
|
||||||
if (webwidget_) {
|
|
||||||
input_method_is_active_ = activated;
|
|
||||||
ime_notification_ = activated;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ime_notification_)
|
if (ime_notification_)
|
||||||
ime_input_.CreateImeWindow(view_);
|
ime_input_.CreateImeWindow(view_);
|
||||||
|
|
||||||
ime_input_.CleanupComposition(view_);
|
ime_input_.CleanupComposition(view_);
|
||||||
ime_input_.SetImeWindowStyle(view_, message, wparam, lparam, &handled);
|
ime_input_.SetImeWindowStyle(view_, message, wparam, lparam, &handled);
|
||||||
|
|
||||||
|
ToggleImeTimer();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1000,7 +976,7 @@ LRESULT WebWidgetHost::OnImeComposition(UINT message, WPARAM wparam,
|
|||||||
ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff);
|
ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff);
|
||||||
|
|
||||||
// Retrieve the result string and its attributes of the ongoing composition
|
// Retrieve the result string and its attributes of the ongoing composition
|
||||||
// and send it to a renderer process.
|
// and send to WebKit.
|
||||||
ui::CompositionText composition;
|
ui::CompositionText composition;
|
||||||
if (ime_input_.GetResult(view_, lparam, &composition.text)) {
|
if (ime_input_.GetResult(view_, lparam, &composition.text)) {
|
||||||
webwidget_->setComposition(composition.text,
|
webwidget_->setComposition(composition.text,
|
||||||
@@ -1014,14 +990,12 @@ LRESULT WebWidgetHost::OnImeComposition(UINT message, WPARAM wparam,
|
|||||||
// by the start of another composition.
|
// by the start of another composition.
|
||||||
}
|
}
|
||||||
// Retrieve the composition string and its attributes of the ongoing
|
// Retrieve the composition string and its attributes of the ongoing
|
||||||
// composition and send it to a renderer process.
|
// composition and send to WebKit.
|
||||||
if (ime_input_.GetComposition(view_, lparam, &composition)) {
|
if (ime_input_.GetComposition(view_, lparam, &composition)) {
|
||||||
// TODO(suzhe): due to a bug of webkit, we can't use selection range with
|
// TODO(suzhe): due to a bug of webkit, we can't use selection range with
|
||||||
// composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788
|
// composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788
|
||||||
composition.selection = ui::Range(composition.selection.end());
|
composition.selection = ui::Range(composition.selection.end());
|
||||||
|
|
||||||
// TODO(suzhe): convert both renderer_host and renderer to use
|
|
||||||
// ui::CompositionText.
|
|
||||||
const std::vector<WebKit::WebCompositionUnderline>& underlines =
|
const std::vector<WebKit::WebCompositionUnderline>& underlines =
|
||||||
reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>(
|
reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>(
|
||||||
composition.underlines);
|
composition.underlines);
|
||||||
@@ -1043,8 +1017,8 @@ LRESULT WebWidgetHost::OnImeEndComposition(UINT message, WPARAM wparam,
|
|||||||
if (ime_input_.is_composing()) {
|
if (ime_input_.is_composing()) {
|
||||||
// A composition has been ended while there is an ongoing composition,
|
// A composition has been ended while there is an ongoing composition,
|
||||||
// i.e. the ongoing composition has been canceled.
|
// i.e. the ongoing composition has been canceled.
|
||||||
// We need to reset the composition status both of the ImeInput object and
|
// Reset the composition status of both of the ImeInput object and the
|
||||||
// of the renderer process.
|
// window.
|
||||||
ime_input_.CancelIME(view_);
|
ime_input_.CancelIME(view_);
|
||||||
ime_input_.ResetComposition(view_);
|
ime_input_.ResetComposition(view_);
|
||||||
}
|
}
|
||||||
@@ -1056,44 +1030,32 @@ LRESULT WebWidgetHost::OnImeEndComposition(UINT message, WPARAM wparam,
|
|||||||
|
|
||||||
void WebWidgetHost::OnInputLangChange(DWORD character_set,
|
void WebWidgetHost::OnInputLangChange(DWORD character_set,
|
||||||
HKL input_language_id) {
|
HKL input_language_id) {
|
||||||
|
if (!webwidget_)
|
||||||
|
return;
|
||||||
|
|
||||||
// Send the given Locale ID to the ImeInput object and retrieves whether
|
// Send the given Locale ID to the ImeInput object and retrieves whether
|
||||||
// or not the current input context has IMEs.
|
// or not the current input context has IMEs. Toggle the timer based on
|
||||||
// If the current input context has IMEs, a browser process has to send a
|
// whether the current input context has IMEs.
|
||||||
// request to a renderer process that it needs status messages about
|
|
||||||
// the focused edit control from the renderer process.
|
|
||||||
// On the other hand, if the current input context does not have IMEs, the
|
|
||||||
// browser process also has to send a request to the renderer process that
|
|
||||||
// it does not need the status messages any longer.
|
|
||||||
// To minimize the number of this notification request, we should check if
|
|
||||||
// the browser process is actually retrieving the status messages (this
|
|
||||||
// state is stored in ime_notification_) and send a request only if the
|
|
||||||
// browser process has to update this status, its details are listed below:
|
|
||||||
// * If a browser process is not retrieving the status messages,
|
|
||||||
// (i.e. ime_notification_ == false),
|
|
||||||
// send this request only if the input context does have IMEs,
|
|
||||||
// (i.e. ime_status == true);
|
|
||||||
// When it successfully sends the request, toggle its notification status,
|
|
||||||
// (i.e.ime_notification_ = !ime_notification_ = true).
|
|
||||||
// * If a browser process is retrieving the status messages
|
|
||||||
// (i.e. ime_notification_ == true),
|
|
||||||
// send this request only if the input context does not have IMEs,
|
|
||||||
// (i.e. ime_status == false).
|
|
||||||
// When it successfully sends the request, toggle its notification status,
|
|
||||||
// (i.e.ime_notification_ = !ime_notification_ = false).
|
|
||||||
// To analyze the above actions, we can optimize them into the ones
|
|
||||||
// listed below:
|
|
||||||
// 1 Sending a request only if ime_status_ != ime_notification_, and;
|
|
||||||
// 2 Copying ime_status to ime_notification_ if it sends the request
|
|
||||||
// successfully (because Action 1 shows ime_status = !ime_notification_.)
|
|
||||||
bool ime_status = ime_input_.SetInputLanguage();
|
bool ime_status = ime_input_.SetInputLanguage();
|
||||||
if (ime_status != ime_notification_ && webwidget_) {
|
if (ime_status != ime_notification_) {
|
||||||
input_method_is_active_ = ime_status;
|
|
||||||
ime_notification_ = ime_status;
|
ime_notification_ = ime_status;
|
||||||
|
ToggleImeTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebWidgetHost::ImeUpdateTextInputState(WebKit::WebTextInputType type,
|
void WebWidgetHost::UpdateImeInputState() {
|
||||||
const gfx::Rect& caret_rect) {
|
if (!webwidget_ || !ime_notification_) {
|
||||||
|
ToggleImeTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebKit::WebTextInputType type = webwidget_->textInputType();
|
||||||
|
WebKit::WebRect caret_bounds;
|
||||||
|
|
||||||
|
WebKit::WebRect startRect, endRect;
|
||||||
|
if (webwidget_->selectionBounds(startRect, endRect))
|
||||||
|
caret_bounds = endRect;
|
||||||
|
|
||||||
if (text_input_type_ != type) {
|
if (text_input_type_ != type) {
|
||||||
text_input_type_ = type;
|
text_input_type_ = type;
|
||||||
if (type == WebKit::WebTextInputTypeText)
|
if (type == WebKit::WebTextInputTypeText)
|
||||||
@@ -1102,31 +1064,24 @@ void WebWidgetHost::ImeUpdateTextInputState(WebKit::WebTextInputType type,
|
|||||||
ime_input_.DisableIME(view_);
|
ime_input_.DisableIME(view_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only update caret position if the input method is enabled.
|
// Only update caret position if the input method is enabled and the caret
|
||||||
if (type == WebKit::WebTextInputTypeText)
|
// position has changed.
|
||||||
ime_input_.UpdateCaretRect(view_, caret_rect);
|
if (type == WebKit::WebTextInputTypeText && caret_bounds != caret_bounds_) {
|
||||||
}
|
caret_bounds_ = caret_bounds;
|
||||||
|
ime_input_.UpdateCaretRect(view_, caret_bounds);
|
||||||
void WebWidgetHost::UpdateInputMethod() {
|
}
|
||||||
REQUIRE_UIT();
|
}
|
||||||
|
|
||||||
has_update_input_method_task_ = false;
|
void WebWidgetHost::ToggleImeTimer() {
|
||||||
|
if (view_ && !popup_ && ime_notification_ && webwidget_) {
|
||||||
if (!input_method_is_active_ || !webwidget_)
|
if (!ime_timer_.IsRunning()) {
|
||||||
return;
|
ime_timer_.Start(
|
||||||
|
FROM_HERE,
|
||||||
WebKit::WebTextInputType new_type = webwidget_->textInputType();
|
base::TimeDelta::FromMilliseconds(200),
|
||||||
WebKit::WebRect new_caret_bounds;
|
this,
|
||||||
|
&WebWidgetHost::UpdateImeInputState);
|
||||||
WebKit::WebRect startRect, endRect;
|
}
|
||||||
if (webwidget_->selectionBounds(startRect, endRect))
|
} else if (ime_timer_.IsRunning()) {
|
||||||
new_caret_bounds = endRect;
|
ime_timer_.Stop();
|
||||||
|
|
||||||
// Only sends text input type and caret bounds to the browser process if they
|
|
||||||
// are changed.
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user