mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
- Win: Improve redraw and scrolling performance (issue #360).
- Win: Fix CefBrowser::GetImage() and add "Get Image" example to cefclient (issue #377). - Pass the list of dirty rectangles to CefRenderHandler::Paint(). (issue #415). git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@368 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
@ -1602,6 +1602,7 @@ class CefRenderHandler : public virtual CefBase
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef cef_paint_element_type_t PaintElementType;
|
typedef cef_paint_element_type_t PaintElementType;
|
||||||
|
typedef std::vector<CefRect> RectList;
|
||||||
|
|
||||||
///
|
///
|
||||||
// Called to retrieve the view rectangle which is relative to screen
|
// Called to retrieve the view rectangle which is relative to screen
|
||||||
@ -1649,14 +1650,14 @@ public:
|
|||||||
///
|
///
|
||||||
// Called when an element should be painted. |type| indicates whether the
|
// Called when an element should be painted. |type| indicates whether the
|
||||||
// element is the view or the popup widget. |buffer| contains the pixel data
|
// element is the view or the popup widget. |buffer| contains the pixel data
|
||||||
// for the whole image. |dirtyRect| indicates the portion of the image that
|
// for the whole image. |dirtyRects| contains the set of rectangles that need
|
||||||
// has been repainted. On Windows |buffer| will be width*height*4 bytes in
|
// to be repainted. On Windows |buffer| will be width*height*4 bytes in size
|
||||||
// size and represents a BGRA image with an upper-left origin.
|
// and represents a BGRA image with an upper-left origin.
|
||||||
///
|
///
|
||||||
/*--cef()--*/
|
/*--cef()--*/
|
||||||
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
|
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
|
||||||
PaintElementType type,
|
PaintElementType type,
|
||||||
const CefRect& dirtyRect,
|
const RectList& dirtyRects,
|
||||||
const void* buffer) {}
|
const void* buffer) {}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -1428,13 +1428,14 @@ typedef struct _cef_render_handler_t
|
|||||||
///
|
///
|
||||||
// Called when an element should be painted. |type| indicates whether the
|
// Called when an element should be painted. |type| indicates whether the
|
||||||
// element is the view or the popup widget. |buffer| contains the pixel data
|
// element is the view or the popup widget. |buffer| contains the pixel data
|
||||||
// for the whole image. |dirtyRect| indicates the portion of the image that
|
// for the whole image. |dirtyRects| contains the set of rectangles that need
|
||||||
// has been repainted. On Windows |buffer| will be width*height*4 bytes in
|
// to be repainted. On Windows |buffer| will be width*height*4 bytes in size
|
||||||
// size and represents a BGRA image with an upper-left origin.
|
// and represents a BGRA image with an upper-left origin.
|
||||||
///
|
///
|
||||||
void (CEF_CALLBACK *on_paint)(struct _cef_render_handler_t* self,
|
void (CEF_CALLBACK *on_paint)(struct _cef_render_handler_t* self,
|
||||||
struct _cef_browser_t* browser, enum cef_paint_element_type_t type,
|
struct _cef_browser_t* browser, enum cef_paint_element_type_t type,
|
||||||
const cef_rect_t* dirtyRect, const void* buffer);
|
size_t dirtyRectCount, cef_rect_t const* dirtyRects,
|
||||||
|
const void* buffer);
|
||||||
|
|
||||||
///
|
///
|
||||||
// Called when the browser window's cursor has changed.
|
// Called when the browser window's cursor has changed.
|
||||||
|
@ -86,9 +86,8 @@ CefBrowserImpl::PaintDelegate::~PaintDelegate()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CefBrowserImpl::PaintDelegate::Paint(bool popup,
|
void CefBrowserImpl::PaintDelegate::Paint(
|
||||||
const gfx::Rect& dirtyRect,
|
bool popup, const std::vector<CefRect>& dirtyRects, const void* buffer)
|
||||||
const void* buffer)
|
|
||||||
{
|
{
|
||||||
CefRefPtr<CefClient> client = browser_->GetClient();
|
CefRefPtr<CefClient> client = browser_->GetClient();
|
||||||
if (!client.get())
|
if (!client.get())
|
||||||
@ -97,9 +96,7 @@ void CefBrowserImpl::PaintDelegate::Paint(bool popup,
|
|||||||
if (!handler.get())
|
if (!handler.get())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CefRect rect(dirtyRect.x(), dirtyRect.y(), dirtyRect.width(),
|
handler->OnPaint(browser_, (popup?PET_POPUP:PET_VIEW), dirtyRects, buffer);
|
||||||
dirtyRect.height());
|
|
||||||
handler->OnPaint(browser_, (popup?PET_POPUP:PET_VIEW), rect, buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1024,8 +1021,15 @@ void CefBrowserImpl::UIT_Invalidate(const CefRect& dirtyRect)
|
|||||||
REQUIRE_UIT();
|
REQUIRE_UIT();
|
||||||
WebViewHost* host = UIT_GetWebViewHost();
|
WebViewHost* host = UIT_GetWebViewHost();
|
||||||
if (host) {
|
if (host) {
|
||||||
host->InvalidateRect(gfx::Rect(dirtyRect.x, dirtyRect.y, dirtyRect.width,
|
gfx::Rect rect(dirtyRect.x, dirtyRect.y, dirtyRect.width,
|
||||||
dirtyRect.height));
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@ public:
|
|||||||
PaintDelegate(CefBrowserImpl* browser);
|
PaintDelegate(CefBrowserImpl* browser);
|
||||||
virtual ~PaintDelegate();
|
virtual ~PaintDelegate();
|
||||||
|
|
||||||
virtual void Paint(bool popup, const gfx::Rect& dirtyRect,
|
virtual void Paint(bool popup, const std::vector<CefRect>& dirtyRects,
|
||||||
const void* buffer);
|
const void* buffer) OVERRIDE;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CefBrowserImpl* browser_;
|
CefBrowserImpl* browser_;
|
||||||
|
@ -21,7 +21,18 @@ void WebWidgetHost::ScheduleAnimation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) {
|
void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) {
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
paint_rgn_.op(rect.x(), rect.y(), rect.right(), rect.bottom(),
|
||||||
|
SkRegion::kUnion_Op);
|
||||||
|
#else
|
||||||
|
// TODO: Update all ports to use regions instead of rectangles.
|
||||||
paint_rect_ = paint_rect_.Union(rect);
|
paint_rect_ = paint_rect_.Union(rect);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebWidgetHost::UpdateRedrawRect(const gfx::Rect& rect) {
|
||||||
|
if (!view_)
|
||||||
|
redraw_rect_ = redraw_rect_.Union(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebWidgetHost::SetSize(int width, int height) {
|
void WebWidgetHost::SetSize(int width, int height) {
|
||||||
@ -80,19 +91,14 @@ gfx::PluginWindowHandle WebWidgetHost::GetWindowedPluginAt(int x, int y)
|
|||||||
void WebWidgetHost::DoPaint() {
|
void WebWidgetHost::DoPaint() {
|
||||||
has_update_task_ = false;
|
has_update_task_ = false;
|
||||||
|
|
||||||
if (update_rect_.IsEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// TODO(cef): The below code is cross-platform but the IsIdle() method
|
// TODO(cef): The below code is cross-platform but the IsIdle() method
|
||||||
// currently requires patches to Chromium. Since this code is only executed
|
// currently requires patches to Chromium. Since this code is only executed
|
||||||
// on Windows it's been stuck behind an #ifdef for now to avoid having to
|
// on Windows it's been stuck behind an #ifdef for now to avoid having to
|
||||||
// patch Chromium code on other platforms.
|
// patch Chromium code on other platforms.
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
if (MessageLoop::current()->IsIdle()) {
|
if (MessageLoop::current()->IsIdle()) {
|
||||||
// Perform the paint.
|
// Paint to the delegate. The rect argument is unused.
|
||||||
UpdatePaintRect(update_rect_);
|
Paint(gfx::Rect());
|
||||||
update_rect_ = gfx::Rect();
|
|
||||||
Paint(update_rect_);
|
|
||||||
} else {
|
} else {
|
||||||
// Try again later.
|
// Try again later.
|
||||||
has_update_task_ = true;
|
has_update_task_ = true;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "include/internal/cef_string.h"
|
#include "include/internal/cef_string.h"
|
||||||
#include "include/internal/cef_types.h"
|
#include "include/internal/cef_types.h"
|
||||||
|
#include "include/internal/cef_types_wrappers.h"
|
||||||
#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/memory/weak_ptr.h"
|
||||||
@ -15,6 +16,7 @@
|
|||||||
#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/WebRect.h"
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h"
|
||||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextInputType.h"
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextInputType.h"
|
||||||
|
#include "third_party/skia/include/core/SkRegion.h"
|
||||||
#include "ui/gfx/native_widget_types.h"
|
#include "ui/gfx/native_widget_types.h"
|
||||||
#include "ui/gfx/rect.h"
|
#include "ui/gfx/rect.h"
|
||||||
#include "webkit/plugins/npapi/webplugin.h"
|
#include "webkit/plugins/npapi/webplugin.h"
|
||||||
@ -53,7 +55,7 @@ class WebWidgetHost {
|
|||||||
public:
|
public:
|
||||||
class PaintDelegate {
|
class PaintDelegate {
|
||||||
public:
|
public:
|
||||||
virtual void Paint(bool popup, const gfx::Rect& dirtyRect,
|
virtual void Paint(bool popup, const std::vector<CefRect>& dirtyRects,
|
||||||
const void* buffer) =0;
|
const void* buffer) =0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -77,10 +79,14 @@ class WebWidgetHost {
|
|||||||
void SetCursor(HCURSOR cursor);
|
void SetCursor(HCURSOR cursor);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Allow clients to update the paint rect. For example, if we get a gdk
|
// Update the region that will be painted to the canvas by WebKit the next
|
||||||
// expose or WM_PAINT event, we need to update the paint rect.
|
// time that Paint() is called.
|
||||||
void UpdatePaintRect(const gfx::Rect& rect);
|
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);
|
||||||
|
|
||||||
void Paint(const gfx::Rect& dirty_rect);
|
void Paint(const gfx::Rect& dirty_rect);
|
||||||
void InvalidateRect(const gfx::Rect& rect);
|
void InvalidateRect(const gfx::Rect& rect);
|
||||||
|
|
||||||
@ -183,8 +189,6 @@ class WebWidgetHost {
|
|||||||
void TrackMouseLeave(bool enable);
|
void TrackMouseLeave(bool enable);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ResetScrollRect();
|
|
||||||
|
|
||||||
void set_painting(bool value) {
|
void set_painting(bool value) {
|
||||||
painting_ = value;
|
painting_ = value;
|
||||||
}
|
}
|
||||||
@ -207,18 +211,19 @@ class WebWidgetHost {
|
|||||||
bool popup_;
|
bool popup_;
|
||||||
|
|
||||||
// Specifies the portion of the webwidget that needs painting.
|
// Specifies the portion of the webwidget that needs painting.
|
||||||
|
// TODO: Update all ports to use regions instead of rectangles.
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
SkRegion paint_rgn_;
|
||||||
|
#else
|
||||||
gfx::Rect paint_rect_;
|
gfx::Rect paint_rect_;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Specifies the portion of the webwidget that needs scrolling.
|
// True if an update task is pending when window rendering is disabled.
|
||||||
gfx::Rect scroll_rect_;
|
|
||||||
int scroll_dx_;
|
|
||||||
int scroll_dy_;
|
|
||||||
|
|
||||||
// Specifies the portion of the webwidget that has been invalidated when
|
|
||||||
// window rendering is disabled.
|
|
||||||
gfx::Rect update_rect_;
|
|
||||||
bool has_update_task_;
|
bool has_update_task_;
|
||||||
|
|
||||||
|
// 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
|
// The map of windowed plugins that need to be drawn when window rendering is
|
||||||
// disabled.
|
// disabled.
|
||||||
typedef std::map<gfx::PluginWindowHandle,webkit::npapi::WebPluginGeometry>
|
typedef std::map<gfx::PluginWindowHandle,webkit::npapi::WebPluginGeometry>
|
||||||
|
@ -322,8 +322,6 @@ WebWidgetHost::WebWidgetHost()
|
|||||||
canvas_w_(0),
|
canvas_w_(0),
|
||||||
canvas_h_(0),
|
canvas_h_(0),
|
||||||
popup_(false),
|
popup_(false),
|
||||||
scroll_dx_(0),
|
|
||||||
scroll_dy_(0),
|
|
||||||
has_update_task_(false),
|
has_update_task_(false),
|
||||||
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
|
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
|
||||||
set_painting(false);
|
set_painting(false);
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.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/WebInputEventFactory.h"
|
||||||
#include "third_party/WebKit/Source/WebKit/chromium/public/win/WebScreenInfoFactory.h"
|
#include "third_party/WebKit/Source/WebKit/chromium/public/win/WebScreenInfoFactory.h"
|
||||||
|
#include "third_party/skia/include/core/SkRegion.h"
|
||||||
#include "ui/base/ime/composition_text.h"
|
#include "ui/base/ime/composition_text.h"
|
||||||
#include "ui/base/range/range.h"
|
#include "ui/base/range/range.h"
|
||||||
#include "ui/base/win/hwnd_util.h"
|
#include "ui/base/win/hwnd_util.h"
|
||||||
@ -66,6 +67,11 @@ void SendMessageToPlugin(HWND hwnd, UINT message, WPARAM wParam,
|
|||||||
EnumChildWindows(hwnd, SendMessageFunc, reinterpret_cast<LPARAM>(&info));
|
EnumChildWindows(hwnd, SendMessageFunc, reinterpret_cast<LPARAM>(&info));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline SkIRect convertToSkiaRect(const gfx::Rect& r)
|
||||||
|
{
|
||||||
|
return SkIRect::MakeLTRB(r.x(), r.y(), r.right(), r.bottom());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
/*static*/
|
/*static*/
|
||||||
@ -117,11 +123,8 @@ LRESULT CALLBACK WebWidgetHost::WndProc(HWND hwnd, UINT message, WPARAM wparam,
|
|||||||
if (host && !host->WndProc(message, wparam, lparam)) {
|
if (host && !host->WndProc(message, wparam, lparam)) {
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case WM_PAINT: {
|
case WM_PAINT: {
|
||||||
// Paint to the window.
|
// Paint to the window. The rect argument is unused.
|
||||||
RECT rect;
|
host->Paint(gfx::Rect());
|
||||||
if (GetUpdateRect(hwnd, &rect, FALSE))
|
|
||||||
host->UpdatePaintRect(gfx::Rect(rect));
|
|
||||||
host->Paint(gfx::Rect(rect));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,15 +268,10 @@ 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";
|
DLOG_IF(WARNING, painting_) << "unexpected invalidation while painting";
|
||||||
|
|
||||||
// If this invalidate overlaps with a pending scroll, then we have to
|
// If this invalidate overlaps with a pending scroll then we have to downgrade
|
||||||
// downgrade to invalidating the scroll rect.
|
// to invalidating the scroll rect.
|
||||||
if (damaged_rect.Intersects(scroll_rect_)) {
|
UpdatePaintRect(damaged_rect);
|
||||||
paint_rect_ = paint_rect_.Union(scroll_rect_);
|
InvalidateRect(damaged_rect);
|
||||||
ResetScrollRect();
|
|
||||||
}
|
|
||||||
paint_rect_ = paint_rect_.Union(damaged_rect);
|
|
||||||
|
|
||||||
InvalidateRect(gfx::Rect(damaged_rect));
|
|
||||||
|
|
||||||
if (!popup_ && view_) {
|
if (!popup_ && view_) {
|
||||||
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableFunction(
|
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableFunction(
|
||||||
@ -282,25 +280,31 @@ void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) {
|
void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) {
|
||||||
if (dx != 0 && dy != 0) {
|
DCHECK(dx || dy);
|
||||||
// We only support uni-directional scroll
|
|
||||||
DidScrollRect(0, dy, clip_rect);
|
// Invalidate and re-paint the entire scroll rect if:
|
||||||
dy = 0;
|
// 1. We're in a state where we cannot draw into the view right now, or
|
||||||
|
// 2. The rect is being scrolled by more than the size of the view, or
|
||||||
|
// 3. The scroll rect intersects the current paint region.
|
||||||
|
if (!canvas_.get() || layouting_ || painting_ ||
|
||||||
|
abs(dx) >= clip_rect.width() || abs(dy) >= clip_rect.height() ||
|
||||||
|
paint_rgn_.intersects(convertToSkiaRect(clip_rect))) {
|
||||||
|
DidInvalidateRect(clip_rect);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we already have a pending scroll operation or if this scroll operation
|
// Scroll the canvas bitmap.
|
||||||
// intersects the existing paint region, then just failover to invalidating.
|
{
|
||||||
if (!scroll_rect_.IsEmpty() || paint_rect_.Intersects(clip_rect)) {
|
skia::ScopedPlatformPaint scoped_platform_paint(canvas_.get());
|
||||||
paint_rect_ = paint_rect_.Union(scroll_rect_);
|
HDC hdc = scoped_platform_paint.GetPlatformSurface();
|
||||||
ResetScrollRect();
|
RECT clip_rect_win32 = clip_rect.ToRECT(), uncovered_rect = {0,0,0,0};
|
||||||
paint_rect_ = paint_rect_.Union(clip_rect);
|
ScrollDC(hdc, dx, dy, NULL, &clip_rect_win32, NULL, &uncovered_rect);
|
||||||
|
|
||||||
|
UpdatePaintRect(gfx::Rect(uncovered_rect));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We will perform scrolling lazily, when requested to actually paint.
|
// Invalidate the scroll rect. It will be drawn from the canvas bitmap on the
|
||||||
scroll_rect_ = clip_rect;
|
// next WM_PAINT call.
|
||||||
scroll_dx_ = dx;
|
|
||||||
scroll_dy_ = dy;
|
|
||||||
|
|
||||||
InvalidateRect(clip_rect);
|
InvalidateRect(clip_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,13 +330,12 @@ WebWidgetHost::WebWidgetHost()
|
|||||||
canvas_h_(0),
|
canvas_h_(0),
|
||||||
popup_(false),
|
popup_(false),
|
||||||
track_mouse_leave_(false),
|
track_mouse_leave_(false),
|
||||||
scroll_dx_(0),
|
|
||||||
scroll_dy_(0),
|
|
||||||
has_update_task_(false),
|
has_update_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),
|
input_method_is_active_(false),
|
||||||
|
layouting_(false),
|
||||||
text_input_type_(WebKit::WebTextInputTypeNone),
|
text_input_type_(WebKit::WebTextInputTypeNone),
|
||||||
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
|
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
|
||||||
set_painting(false);
|
set_painting(false);
|
||||||
@ -359,14 +362,19 @@ bool WebWidgetHost::WndProc(UINT message, WPARAM wparam, LPARAM lparam) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebWidgetHost::Paint(const gfx::Rect& dirty_rect) {
|
void WebWidgetHost::Paint(const gfx::Rect& /*dirty_rect*/) {
|
||||||
if (canvas_.get() && paint_rect_.IsEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
int width, height;
|
int width, height;
|
||||||
GetSize(width, height);
|
GetSize(width, height);
|
||||||
gfx::Rect client_rect(width, height);
|
gfx::Rect client_rect(width, height);
|
||||||
gfx::Rect damaged_rect;
|
|
||||||
|
// 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()) {
|
if (view_ && !webwidget_->isAcceleratedCompositingActive()) {
|
||||||
// Number of pixels that the canvas is allowed to differ from the client
|
// Number of pixels that the canvas is allowed to differ from the client
|
||||||
@ -378,8 +386,7 @@ void WebWidgetHost::Paint(const gfx::Rect& dirty_rect) {
|
|||||||
canvas_h_ < client_rect.height() ||
|
canvas_h_ < client_rect.height() ||
|
||||||
canvas_w_ > client_rect.width() + kCanvasGrowSize * 2 ||
|
canvas_w_ > client_rect.width() + kCanvasGrowSize * 2 ||
|
||||||
canvas_h_ > client_rect.height() + kCanvasGrowSize * 2) {
|
canvas_h_ > client_rect.height() + kCanvasGrowSize * 2) {
|
||||||
ResetScrollRect();
|
paint_rgn_.setRect(convertToSkiaRect(client_rect));
|
||||||
paint_rect_ = client_rect;
|
|
||||||
|
|
||||||
// Resize the canvas to be within a reasonable size of the client area.
|
// Resize the canvas to be within a reasonable size of the client area.
|
||||||
canvas_w_ = client_rect.width() + kCanvasGrowSize;
|
canvas_w_ = client_rect.width() + kCanvasGrowSize;
|
||||||
@ -388,8 +395,7 @@ void WebWidgetHost::Paint(const gfx::Rect& dirty_rect) {
|
|||||||
}
|
}
|
||||||
} else if(!canvas_.get() || canvas_w_ != client_rect.width() ||
|
} else if(!canvas_.get() || canvas_w_ != client_rect.width() ||
|
||||||
canvas_h_ != client_rect.height()) {
|
canvas_h_ != client_rect.height()) {
|
||||||
ResetScrollRect();
|
paint_rgn_.setRect(convertToSkiaRect(client_rect));
|
||||||
paint_rect_ = client_rect;
|
|
||||||
|
|
||||||
// The canvas must be the exact size of the client area.
|
// The canvas must be the exact size of the client area.
|
||||||
canvas_w_ = client_rect.width();
|
canvas_w_ = client_rect.width();
|
||||||
@ -397,41 +403,40 @@ void WebWidgetHost::Paint(const gfx::Rect& dirty_rect) {
|
|||||||
canvas_.reset(new skia::PlatformCanvas(canvas_w_, canvas_h_, true));
|
canvas_.reset(new skia::PlatformCanvas(canvas_w_, canvas_h_, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layouting_ = true;
|
||||||
webwidget_->animate(0.0);
|
webwidget_->animate(0.0);
|
||||||
|
|
||||||
// This may result in more invalidation
|
// This may result in more invalidation.
|
||||||
webwidget_->layout();
|
webwidget_->layout();
|
||||||
|
|
||||||
// Scroll the canvas if necessary
|
layouting_ = false;
|
||||||
scroll_rect_ = client_rect.Intersect(scroll_rect_);
|
|
||||||
if (!scroll_rect_.IsEmpty()) {
|
|
||||||
skia::ScopedPlatformPaint scoped_platform_paint(canvas_.get());
|
|
||||||
HDC hdc = scoped_platform_paint.GetPlatformSurface();
|
|
||||||
|
|
||||||
RECT damaged_scroll_rect, r = scroll_rect_.ToRECT();
|
// Paint the canvas if necessary. Allow painting to generate extra rects the
|
||||||
ScrollDC(hdc, scroll_dx_, scroll_dy_, NULL, &r, NULL, &damaged_scroll_rect);
|
// first time we call it. This is necessary because some WebCore rendering
|
||||||
|
|
||||||
PaintRect(gfx::Rect(damaged_scroll_rect));
|
|
||||||
}
|
|
||||||
ResetScrollRect();
|
|
||||||
|
|
||||||
// Paint the canvas if necessary. Allow painting to generate extra rects the
|
|
||||||
// first time we call it. This is necessary because some WebCore rendering
|
|
||||||
// objects update their layout only when painted.
|
// objects update their layout only when painted.
|
||||||
for (int i = 0; i < 2; ++i) {
|
for (int i = 0; i < 2; ++i) {
|
||||||
paint_rect_ = client_rect.Intersect(paint_rect_);
|
SkRegion draw_rgn;
|
||||||
damaged_rect = damaged_rect.Union(paint_rect_);
|
draw_rgn.swap(paint_rgn_);
|
||||||
if (!paint_rect_.IsEmpty()) {
|
|
||||||
gfx::Rect rect(paint_rect_);
|
|
||||||
paint_rect_ = gfx::Rect();
|
|
||||||
|
|
||||||
DLOG_IF(WARNING, i == 1) << "painting caused additional invalidations";
|
// Draw each dirty rect in the region.
|
||||||
PaintRect(rect);
|
SkRegion::Cliperator iterator(draw_rgn, convertToSkiaRect(client_rect));
|
||||||
|
for (; !iterator.done(); iterator.next()) {
|
||||||
|
const SkIRect& r = iterator.rect();
|
||||||
|
gfx::Rect paint_rect =
|
||||||
|
gfx::Rect(r.left(), r.top(), r.width(), r.height());
|
||||||
|
PaintRect(paint_rect);
|
||||||
|
|
||||||
|
if (!view_)
|
||||||
|
damaged_rgn.op(convertToSkiaRect(paint_rect), SkRegion::kUnion_Op);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
DCHECK(paint_rect_.IsEmpty());
|
|
||||||
|
|
||||||
if (plugin_map_.size() > 0) {
|
if (paint_rgn_.isEmpty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK(paint_rgn_.isEmpty());
|
||||||
|
|
||||||
|
if (!view_ && plugin_map_.size() > 0) {
|
||||||
typedef std::list<const WebPluginGeometry*> PluginList;
|
typedef std::list<const WebPluginGeometry*> PluginList;
|
||||||
PluginList visible_plugins;
|
PluginList visible_plugins;
|
||||||
|
|
||||||
@ -476,11 +481,14 @@ void WebWidgetHost::Paint(const gfx::Rect& dirty_rect) {
|
|||||||
SetViewportOrgEx(drawDC, oldViewport.x, oldViewport.y, NULL);
|
SetViewportOrgEx(drawDC, oldViewport.x, oldViewport.y, NULL);
|
||||||
SelectClipRgn(drawDC, oldRGN);
|
SelectClipRgn(drawDC, oldRGN);
|
||||||
|
|
||||||
damaged_rect = damaged_rect.Union(geom->window_rect);
|
if (!view_) {
|
||||||
}
|
damaged_rgn.op(convertToSkiaRect(geom->window_rect),
|
||||||
|
SkRegion::kUnion_Op);
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure the damaged rectangle is inside the client rectangle.
|
DeleteObject(oldRGN);
|
||||||
damaged_rect = damaged_rect.Intersect(client_rect);
|
DeleteObject(newRGN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,13 +502,22 @@ void WebWidgetHost::Paint(const gfx::Rect& dirty_rect) {
|
|||||||
|
|
||||||
// Draw children
|
// Draw children
|
||||||
UpdateWindow(view_);
|
UpdateWindow(view_);
|
||||||
} else {
|
} else if(!damaged_rgn.isEmpty()) {
|
||||||
// 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);
|
||||||
DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
|
DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
|
||||||
const void* pixels = bitmap.getPixels();
|
const void* pixels = bitmap.getPixels();
|
||||||
paint_delegate_->Paint(popup_, damaged_rect, pixels);
|
|
||||||
|
std::vector<CefRect> damaged_rects;
|
||||||
|
SkRegion::Cliperator iterator(damaged_rgn, convertToSkiaRect(client_rect));
|
||||||
|
for (; !iterator.done(); iterator.next()) {
|
||||||
|
const SkIRect& r = iterator.rect();
|
||||||
|
damaged_rects.push_back(
|
||||||
|
CefRect(r.left(), r.top(), r.width(), r.height()));
|
||||||
|
}
|
||||||
|
|
||||||
|
paint_delegate_->Paint(popup_, damaged_rects, pixels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,12 +528,10 @@ void WebWidgetHost::InvalidateRect(const gfx::Rect& rect)
|
|||||||
|
|
||||||
if (view_) {
|
if (view_) {
|
||||||
// Let the window handle painting.
|
// Let the window handle painting.
|
||||||
RECT r = {rect.x(), rect.y(), rect.x() + rect.width(),
|
RECT r = rect.ToRECT();
|
||||||
rect.y() + rect.height()};
|
|
||||||
::InvalidateRect(view_, &r, FALSE);
|
::InvalidateRect(view_, &r, FALSE);
|
||||||
} else {
|
} else {
|
||||||
// The update rectangle will be painted by DoPaint().
|
// Paint() will be called by DoPaint().
|
||||||
update_rect_ = update_rect_.Union(rect);
|
|
||||||
if (!has_update_task_) {
|
if (!has_update_task_) {
|
||||||
has_update_task_ = true;
|
has_update_task_ = true;
|
||||||
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
||||||
@ -527,15 +542,28 @@ void WebWidgetHost::InvalidateRect(const gfx::Rect& rect)
|
|||||||
|
|
||||||
bool WebWidgetHost::GetImage(int width, int height, void* buffer)
|
bool WebWidgetHost::GetImage(int width, int height, void* buffer)
|
||||||
{
|
{
|
||||||
if (!canvas_.get())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
DCHECK(width == canvas_->getDevice()->width());
|
|
||||||
DCHECK(height == canvas_->getDevice()->height());
|
|
||||||
|
|
||||||
const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false);
|
const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false);
|
||||||
DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
|
DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
|
||||||
const void* pixels = bitmap.getPixels();
|
|
||||||
|
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<skia::PlatformCanvas> 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);
|
memcpy(buffer, pixels, width * height * 4);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -704,12 +732,6 @@ void WebWidgetHost::TrackMouseLeave(bool track) {
|
|||||||
TrackMouseEvent(&tme);
|
TrackMouseEvent(&tme);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebWidgetHost::ResetScrollRect() {
|
|
||||||
scroll_rect_ = gfx::Rect();
|
|
||||||
scroll_dx_ = 0;
|
|
||||||
scroll_dy_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebWidgetHost::PaintRect(const gfx::Rect& rect) {
|
void WebWidgetHost::PaintRect(const gfx::Rect& rect) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
DCHECK(!painting_);
|
DCHECK(!painting_);
|
||||||
|
@ -94,18 +94,22 @@ void CEF_CALLBACK render_handler_on_popup_size(
|
|||||||
|
|
||||||
void CEF_CALLBACK render_handler_on_paint(struct _cef_render_handler_t* self,
|
void CEF_CALLBACK render_handler_on_paint(struct _cef_render_handler_t* self,
|
||||||
cef_browser_t* browser, enum cef_paint_element_type_t type,
|
cef_browser_t* browser, enum cef_paint_element_type_t type,
|
||||||
const cef_rect_t* dirtyRect, const void* buffer)
|
size_t dirtyRectCount, cef_rect_t const* dirtyRects, const void* buffer)
|
||||||
{
|
{
|
||||||
DCHECK(self);
|
DCHECK(self);
|
||||||
DCHECK(browser);
|
DCHECK(browser);
|
||||||
DCHECK(dirtyRect);
|
DCHECK(dirtyRectCount > 0);
|
||||||
|
DCHECK(dirtyRects);
|
||||||
DCHECK(buffer);
|
DCHECK(buffer);
|
||||||
if (!self || !browser || !dirtyRect || !buffer)
|
if (!self || !browser || dirtyRectCount == 0 || !dirtyRects || !buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CefRect rect(*dirtyRect);
|
CefRenderHandler::RectList rectList;
|
||||||
|
for (size_t i = 0; i < dirtyRectCount; ++i)
|
||||||
|
rectList.push_back(dirtyRects[i]);
|
||||||
|
|
||||||
return CefRenderHandlerCppToC::Get(self)->OnPaint(
|
return CefRenderHandlerCppToC::Get(self)->OnPaint(
|
||||||
CefBrowserCToCpp::Wrap(browser), type, rect, buffer);
|
CefBrowserCToCpp::Wrap(browser), type, rectList, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEF_CALLBACK render_handler_on_cursor_change(
|
void CEF_CALLBACK render_handler_on_cursor_change(
|
||||||
|
@ -66,13 +66,25 @@ void CefRenderHandlerCToCpp::OnPopupSize(CefRefPtr<CefBrowser> browser,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CefRenderHandlerCToCpp::OnPaint(CefRefPtr<CefBrowser> browser,
|
void CefRenderHandlerCToCpp::OnPaint(CefRefPtr<CefBrowser> browser,
|
||||||
PaintElementType type, const CefRect& dirtyRect, const void* buffer)
|
PaintElementType type, const RectList& dirtyRects, const void* buffer)
|
||||||
{
|
{
|
||||||
if (CEF_MEMBER_MISSING(struct_, on_paint))
|
if (CEF_MEMBER_MISSING(struct_, on_paint))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
return struct_->on_paint(struct_, CefBrowserCppToC::Wrap(browser), type,
|
const size_t rectCt = dirtyRects.size();
|
||||||
&dirtyRect, buffer);
|
DCHECK(rectCt > 0);
|
||||||
|
if (rectCt == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cef_rect_t* rects = new cef_rect_t[rectCt];
|
||||||
|
RectList::const_iterator it = dirtyRects.begin();
|
||||||
|
for (size_t i = 0; it != dirtyRects.end(); ++it, ++i)
|
||||||
|
rects[i] = *it;
|
||||||
|
|
||||||
|
struct_->on_paint(struct_, CefBrowserCppToC::Wrap(browser), type, rectCt,
|
||||||
|
rects, buffer);
|
||||||
|
|
||||||
|
delete [] rects;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CefRenderHandlerCToCpp::OnCursorChange(CefRefPtr<CefBrowser> browser,
|
void CefRenderHandlerCToCpp::OnCursorChange(CefRefPtr<CefBrowser> browser,
|
||||||
|
@ -43,7 +43,7 @@ public:
|
|||||||
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
|
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
|
||||||
const CefRect& rect) OVERRIDE;
|
const CefRect& rect) OVERRIDE;
|
||||||
virtual void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type,
|
virtual void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type,
|
||||||
const CefRect& dirtyRect, const void* buffer) OVERRIDE;
|
const RectList& dirtyRects, const void* buffer) OVERRIDE;
|
||||||
virtual void OnCursorChange(CefRefPtr<CefBrowser> browser,
|
virtual void OnCursorChange(CefRefPtr<CefBrowser> browser,
|
||||||
CefCursorHandle cursor) OVERRIDE;
|
CefCursorHandle cursor) OVERRIDE;
|
||||||
};
|
};
|
||||||
|
@ -36,6 +36,7 @@ void RunModalDialogTest(CefRefPtr<CefBrowser> browser);
|
|||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
void RunTransparentPopupTest(CefRefPtr<CefBrowser> browser);
|
void RunTransparentPopupTest(CefRefPtr<CefBrowser> browser);
|
||||||
|
void RunGetImageTest(CefRefPtr<CefBrowser> browser);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // _CEFCLIENT_H
|
#endif // _CEFCLIENT_H
|
||||||
|
@ -101,6 +101,7 @@ BEGIN
|
|||||||
MENUITEM "Show Developer Tools", ID_TESTS_DEVTOOLS_SHOW
|
MENUITEM "Show Developer Tools", ID_TESTS_DEVTOOLS_SHOW
|
||||||
MENUITEM "Close Developer Tools", ID_TESTS_DEVTOOLS_CLOSE
|
MENUITEM "Close Developer Tools", ID_TESTS_DEVTOOLS_CLOSE
|
||||||
MENUITEM "Modal Dialog", ID_TESTS_MODALDIALOG
|
MENUITEM "Modal Dialog", ID_TESTS_MODALDIALOG
|
||||||
|
MENUITEM "Get Image", ID_TESTS_GETIMAGE
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// can be found in the LICENSE file.
|
// can be found in the LICENSE file.
|
||||||
|
|
||||||
#include "include/cef.h"
|
#include "include/cef.h"
|
||||||
|
#include "include/cef_runnable.h"
|
||||||
#include "cefclient.h"
|
#include "cefclient.h"
|
||||||
#include "binding_test.h"
|
#include "binding_test.h"
|
||||||
#include "client_handler.h"
|
#include "client_handler.h"
|
||||||
@ -17,6 +18,7 @@
|
|||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <shellapi.h>
|
||||||
|
|
||||||
#define MAX_LOADSTRING 100
|
#define MAX_LOADSTRING 100
|
||||||
#define MAX_URL_LENGTH 255
|
#define MAX_URL_LENGTH 255
|
||||||
@ -583,6 +585,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
if(browser.get())
|
if(browser.get())
|
||||||
RunModalDialogTest(browser);
|
RunModalDialogTest(browser);
|
||||||
return 0;
|
return 0;
|
||||||
|
case ID_TESTS_GETIMAGE:
|
||||||
|
if(browser.get())
|
||||||
|
RunGetImageTest(browser);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -694,3 +700,112 @@ void RunTransparentPopupTest(CefRefPtr<CefBrowser> browser)
|
|||||||
static_cast<CefRefPtr<CefClient> >(g_handler),
|
static_cast<CefRefPtr<CefClient> >(g_handler),
|
||||||
"http://tests/transparency", settings);
|
"http://tests/transparency", settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Determine a temporary path for the bitmap file.
|
||||||
|
bool GetBitmapTempPath(LPWSTR szTempName)
|
||||||
|
{
|
||||||
|
DWORD dwRetVal;
|
||||||
|
DWORD dwBufSize = 512;
|
||||||
|
TCHAR lpPathBuffer[512];
|
||||||
|
UINT uRetVal;
|
||||||
|
|
||||||
|
dwRetVal = GetTempPath(dwBufSize, // length of the buffer
|
||||||
|
lpPathBuffer); // buffer for path
|
||||||
|
if (dwRetVal > dwBufSize || (dwRetVal == 0))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Create a temporary file.
|
||||||
|
uRetVal = GetTempFileName(lpPathBuffer, // directory for tmp files
|
||||||
|
L"image", // temp file name prefix
|
||||||
|
0, // create unique name
|
||||||
|
szTempName); // buffer for name
|
||||||
|
if (uRetVal == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t len = wcslen(szTempName);
|
||||||
|
wcscpy(szTempName + len - 3, L"bmp");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIT_RunGetImageTest(CefRefPtr<CefBrowser> browser)
|
||||||
|
{
|
||||||
|
REQUIRE_UI_THREAD();
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
// Retrieve the image size.
|
||||||
|
if (browser->GetSize(PET_VIEW, width, height)) {
|
||||||
|
void* bits;
|
||||||
|
|
||||||
|
// Populate the bitmap info header.
|
||||||
|
BITMAPINFOHEADER info;
|
||||||
|
info.biSize = sizeof(BITMAPINFOHEADER);
|
||||||
|
info.biWidth = width;
|
||||||
|
info.biHeight = -height; // minus means top-down bitmap
|
||||||
|
info.biPlanes = 1;
|
||||||
|
info.biBitCount = 32;
|
||||||
|
info.biCompression = BI_RGB; // no compression
|
||||||
|
info.biSizeImage = 0;
|
||||||
|
info.biXPelsPerMeter = 1;
|
||||||
|
info.biYPelsPerMeter = 1;
|
||||||
|
info.biClrUsed = 0;
|
||||||
|
info.biClrImportant = 0;
|
||||||
|
|
||||||
|
// Create the bitmap and retrieve the bit buffer.
|
||||||
|
HDC screen_dc = GetDC(NULL);
|
||||||
|
HBITMAP bitmap =
|
||||||
|
CreateDIBSection(screen_dc, reinterpret_cast<BITMAPINFO*>(&info),
|
||||||
|
DIB_RGB_COLORS, &bits, NULL, 0);
|
||||||
|
ReleaseDC(NULL, screen_dc);
|
||||||
|
|
||||||
|
// Read the image into the bit buffer.
|
||||||
|
if (bitmap && browser->GetImage(PET_VIEW, width, height, bits)) {
|
||||||
|
// Populate the bitmap file header.
|
||||||
|
BITMAPFILEHEADER file;
|
||||||
|
file.bfType = 0x4d42;
|
||||||
|
file.bfSize = sizeof(BITMAPFILEHEADER);
|
||||||
|
file.bfReserved1 = 0;
|
||||||
|
file.bfReserved2 = 0;
|
||||||
|
file.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
||||||
|
|
||||||
|
TCHAR temp_path[512];
|
||||||
|
if (GetBitmapTempPath(temp_path)) {
|
||||||
|
// Write the bitmap to file.
|
||||||
|
HANDLE file_handle =
|
||||||
|
CreateFile(temp_path, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
|
||||||
|
FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
if (file_handle != INVALID_HANDLE_VALUE) {
|
||||||
|
DWORD bytes_written = 0;
|
||||||
|
WriteFile(file_handle, &file, sizeof(file), &bytes_written, 0);
|
||||||
|
WriteFile(file_handle, &info, sizeof(info), &bytes_written, 0);
|
||||||
|
WriteFile(file_handle, bits, width * height * 4, &bytes_written, 0);
|
||||||
|
|
||||||
|
CloseHandle(file_handle);
|
||||||
|
|
||||||
|
// Open the bitmap in the default viewer.
|
||||||
|
ShellExecute(NULL, L"open", temp_path, NULL, NULL, SW_SHOWNORMAL);
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteObject(bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
browser->GetMainFrame()->ExecuteJavaScript(
|
||||||
|
"alert('Failed to create image!');",
|
||||||
|
browser->GetMainFrame()->GetURL(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void RunGetImageTest(CefRefPtr<CefBrowser> browser)
|
||||||
|
{
|
||||||
|
// Execute the test function on the UI thread.
|
||||||
|
CefPostTask(TID_UI, NewCefRunnableFunction(UIT_RunGetImageTest, browser));
|
||||||
|
}
|
||||||
|
@ -280,7 +280,7 @@ public:
|
|||||||
|
|
||||||
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
|
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
|
||||||
PaintElementType type,
|
PaintElementType type,
|
||||||
const CefRect& dirtyRect,
|
const RectList& dirtyRects,
|
||||||
const void* buffer) OVERRIDE
|
const void* buffer) OVERRIDE
|
||||||
{
|
{
|
||||||
REQUIRE_UI_THREAD();
|
REQUIRE_UI_THREAD();
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
#define ID_TESTS_TRANSPARENT_POPUP 32796
|
#define ID_TESTS_TRANSPARENT_POPUP 32796
|
||||||
#define ID_TESTS_TRANSPARENT_OSRAPP 32797
|
#define ID_TESTS_TRANSPARENT_OSRAPP 32797
|
||||||
#define ID_TESTS_JAVASCRIPT_INVOKE 32798
|
#define ID_TESTS_JAVASCRIPT_INVOKE 32798
|
||||||
|
#define ID_TESTS_GETIMAGE 32799
|
||||||
#define IDC_STATIC -1
|
#define IDC_STATIC -1
|
||||||
#define IDS_LOGO 1000
|
#define IDS_LOGO 1000
|
||||||
#define IDS_UIPLUGIN 1001
|
#define IDS_UIPLUGIN 1001
|
||||||
|
@ -1203,7 +1203,10 @@ class obj_analysis:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
if type == 'simple':
|
if type == 'simple':
|
||||||
result['value'] = value
|
str = value
|
||||||
|
if self.is_const():
|
||||||
|
str += ' const*'
|
||||||
|
result['value'] = str
|
||||||
elif type == 'refptr':
|
elif type == 'refptr':
|
||||||
str = ''
|
str = ''
|
||||||
if not value[:-1] in defined_structs:
|
if not value[:-1] in defined_structs:
|
||||||
|
Reference in New Issue
Block a user