Merge pull request #128 from atom/api-capture-page

Add BrowserWindow.capturePage API.
This commit is contained in:
Cheng Zhao 2013-11-21 22:52:22 -08:00
commit 5720d4f802
8 changed files with 121 additions and 6 deletions

View file

@ -14,6 +14,7 @@
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "vendor/node/src/node_buffer.h"
using content::V8ValueConverter;
using content::NavigationController;
@ -82,6 +83,20 @@ void Window::OnRendererCrashed() {
Emit("crashed");
}
void Window::OnCapturePageDone(v8::Persistent<v8::Function> callback,
const std::vector<unsigned char>& data) {
v8::HandleScope scope;
// TODO(zcbenz): Use new Buffer API when we updated to node v0.12.x.
node::Buffer* buffer = node::Buffer::New(
reinterpret_cast<const char*>(data.data()),
data.size());
v8::Handle<v8::Value> arg = buffer->handle_;
callback->Call(v8::Context::GetCurrent()->Global(), 1, &arg);
callback.Dispose(v8::Isolate::GetCurrent());
}
// static
v8::Handle<v8::Value> Window::New(const v8::Arguments &args) {
v8::HandleScope scope;
@ -480,6 +495,23 @@ v8::Handle<v8::Value> Window::RestartHangMonitorTimeout(
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::CapturePage(const v8::Arguments& args) {
UNWRAP_WINDOW_AND_CHECK;
gfx::Rect rect;
v8::Persistent<v8::Function> callback;
if (!FromV8Arguments(args, &rect, &callback) &&
!FromV8Arguments(args, &callback))
return node::ThrowTypeError("Bad argument");
self->window_->CapturePage(rect, base::Bind(&Window::OnCapturePageDone,
base::Unretained(self),
callback));
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::GetPageTitle(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
@ -721,6 +753,7 @@ void Window::Initialize(v8::Handle<v8::Object> target) {
NODE_SET_PROTOTYPE_METHOD(t,
"restartHangMonitorTimeout",
RestartHangMonitorTimeout);
NODE_SET_PROTOTYPE_METHOD(t, "capturePage", CapturePage);
NODE_SET_PROTOTYPE_METHOD(t, "getPageTitle", GetPageTitle);
NODE_SET_PROTOTYPE_METHOD(t, "isLoading", IsLoading);

View file

@ -5,6 +5,8 @@
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "browser/api/atom_api_event_emitter.h"
#include "browser/native_window_observer.h"
@ -87,6 +89,7 @@ class Window : public EventEmitter,
static v8::Handle<v8::Value> IsWebViewFocused(const v8::Arguments& args);
static v8::Handle<v8::Value> RestartHangMonitorTimeout(
const v8::Arguments &args);
static v8::Handle<v8::Value> CapturePage(const v8::Arguments& args);
// APIs for WebContents.
static v8::Handle<v8::Value> GetPageTitle(const v8::Arguments &args);
@ -110,6 +113,10 @@ class Window : public EventEmitter,
static v8::Handle<v8::Value> Reload(const v8::Arguments &args);
static v8::Handle<v8::Value> ReloadIgnoringCache(const v8::Arguments &args);
// Called when capturePage is done.
void OnCapturePageDone(v8::Persistent<v8::Function> callback,
const std::vector<unsigned char>& data);
scoped_ptr<NativeWindow> window_;
DISALLOW_COPY_AND_ASSIGN(Window);

View file

@ -29,6 +29,7 @@
#include "common/api/api_messages.h"
#include "common/options_switches.h"
#include "ipc/ipc_message_macros.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
@ -198,6 +199,16 @@ bool NativeWindow::SetIcon(const std::string& str_path) {
return true;
}
void NativeWindow::CapturePage(const gfx::Rect& rect,
const CapturePageCallback& callback) {
GetWebContents()->GetRenderViewHost()->CopyFromBackingStore(
rect,
gfx::Size(),
base::Bind(&NativeWindow::OnCapturePageDone,
base::Unretained(this),
callback));
}
void NativeWindow::CloseWebContents() {
bool prevent_default = false;
FOR_EACH_OBSERVER(NativeWindowObserver,
@ -374,6 +385,15 @@ void NativeWindow::Observe(int type,
}
}
void NativeWindow::OnCapturePageDone(const CapturePageCallback& callback,
bool succeed,
const SkBitmap& bitmap) {
std::vector<unsigned char> data;
if (succeed)
gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &data);
callback.Run(data);
}
void NativeWindow::OnRendererMessage(const string16& channel,
const base::ListValue& args) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(

View file

@ -49,6 +49,9 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
public content::WebContentsObserver,
public content::NotificationObserver {
public:
typedef base::Callback<void(const std::vector<unsigned char>& buffer)>
CapturePageCallback;
virtual ~NativeWindow();
// Create window with existing WebContents.
@ -108,6 +111,11 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void RestartHangMonitorTimeout();
virtual bool SetIcon(const std::string& path);
// Captures the page with |rect|, |callback| would be called when capturing is
// done.
virtual void CapturePage(const gfx::Rect& rect,
const CapturePageCallback& callback);
// The same with closing a tab in a real browser.
//
// Should be called by platform code when user want to close the window.
@ -184,6 +192,11 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
private:
void RendererUnresponsiveDelayed();
// Called when CapturePage has done.
void OnCapturePageDone(const CapturePageCallback& callback,
bool succeed,
const SkBitmap& bitmap);
void OnRendererMessage(const string16& channel,
const base::ListValue& args);

View file

@ -11,6 +11,7 @@
#include "base/files/file_path.h"
#include "base/string16.h"
#include "browser/api/atom_api_window.h"
#include "ui/gfx/rect.h"
#include "v8/include/v8.h"
// Convert V8 value to arbitrary supported types.
@ -38,6 +39,20 @@ struct FromV8Value {
return base::FilePath::FromUTF8Unsafe(FromV8Value(value_));
}
operator gfx::Rect() {
v8::Handle<v8::Object> rect = value_->ToObject();
v8::Handle<v8::Value> x = rect->Get(v8::String::New("x"));
v8::Handle<v8::Value> y = rect->Get(v8::String::New("y"));
v8::Handle<v8::Value> width = rect->Get(v8::String::New("width"));
v8::Handle<v8::Value> height = rect->Get(v8::String::New("height"));
if (!x->IsNumber() || !y->IsNumber() ||
!width->IsNumber() || !height->IsNumber())
return gfx::Rect();
else
return gfx::Rect(x->IntegerValue(), y->IntegerValue(),
width->IntegerValue(), height->IntegerValue());
}
operator std::vector<std::string>() {
std::vector<std::string> array;
v8::Handle<v8::Array> v8_array = v8::Handle<v8::Array>::Cast(value_);
@ -58,11 +73,9 @@ struct FromV8Value {
}
operator v8::Persistent<v8::Function>() {
return value_->IsFunction() ?
v8::Persistent<v8::Function>::New(
node::node_isolate,
v8::Handle<v8::Function>::Cast(value_)) :
v8::Persistent<v8::Function>();
return v8::Persistent<v8::Function>::New(
node::node_isolate,
v8::Handle<v8::Function>::Cast(value_));
}
v8::Handle<v8::Value> value_;
@ -137,6 +150,11 @@ bool V8ValueCanBeConvertedTo<base::FilePath>(v8::Handle<v8::Value> value) {
return V8ValueCanBeConvertedTo<std::string>(value);
}
template<> inline
bool V8ValueCanBeConvertedTo<gfx::Rect>(v8::Handle<v8::Value> value) {
return value->IsObject();
}
template<> inline
bool V8ValueCanBeConvertedTo<std::vector<std::string>>(
v8::Handle<v8::Value> value) {

View file

@ -290,6 +290,23 @@ Starts inspecting element at position (`x`, `y`).
### BrowserWindow.restartHangMonitorTimeout()
### BrowserWindow.capturePage([rect, ]callback)
* `rect` Object - The area of page to be captured
* `x`
* `y`
* `width`
* `height`
* `callback` Function
Captures the snapshot of page within `rect`, upon completion `callback` would be
called with `callback(image)`, the `image` is a `Buffer` that stores the PNG
encoded data of the snapshot. Omitting the `rect` would capture the whole
visible page.
You can write received `image` directly to a `.png` file, or you can base64
encode it and use data URL to embed the image in HTML.
### BrowserWindow.getPageTitle()
Returns the title of web page.

View file

@ -75,6 +75,13 @@ describe 'window module', ->
assert.equal w.isVisible(), false
w.close()
describe 'BrowserWindow.capturePage(rect, callback)', ->
it 'calls the callback with a Buffer', ->
w = new BrowserWindow(show: false)
w.capturePage {x: 0, y: 0, width: 100, height: 100}, (image) ->
assert.equal image.constructor.name, 'SlowBuffer'
w.close()
describe 'beforeunload handler', ->
it 'returning true would not prevent close', (done) ->
w = new BrowserWindow(show: false)

2
vendor/node vendored

@ -1 +1 @@
Subproject commit 7f44fac0fd64af7ec172c9606af1f3cec684a9ce
Subproject commit 24c11bdc794c2b7b79163cb4737046f8de42446d