Merge pull request #128 from atom/api-capture-page
Add BrowserWindow.capturePage API.
This commit is contained in:
commit
5720d4f802
8 changed files with 121 additions and 6 deletions
|
@ -14,6 +14,7 @@
|
||||||
#include "ui/gfx/point.h"
|
#include "ui/gfx/point.h"
|
||||||
#include "ui/gfx/rect.h"
|
#include "ui/gfx/rect.h"
|
||||||
#include "ui/gfx/size.h"
|
#include "ui/gfx/size.h"
|
||||||
|
#include "vendor/node/src/node_buffer.h"
|
||||||
|
|
||||||
using content::V8ValueConverter;
|
using content::V8ValueConverter;
|
||||||
using content::NavigationController;
|
using content::NavigationController;
|
||||||
|
@ -82,6 +83,20 @@ void Window::OnRendererCrashed() {
|
||||||
Emit("crashed");
|
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
|
// static
|
||||||
v8::Handle<v8::Value> Window::New(const v8::Arguments &args) {
|
v8::Handle<v8::Value> Window::New(const v8::Arguments &args) {
|
||||||
v8::HandleScope scope;
|
v8::HandleScope scope;
|
||||||
|
@ -480,6 +495,23 @@ v8::Handle<v8::Value> Window::RestartHangMonitorTimeout(
|
||||||
return v8::Undefined();
|
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
|
// static
|
||||||
v8::Handle<v8::Value> Window::GetPageTitle(const v8::Arguments &args) {
|
v8::Handle<v8::Value> Window::GetPageTitle(const v8::Arguments &args) {
|
||||||
UNWRAP_WINDOW_AND_CHECK;
|
UNWRAP_WINDOW_AND_CHECK;
|
||||||
|
@ -721,6 +753,7 @@ void Window::Initialize(v8::Handle<v8::Object> target) {
|
||||||
NODE_SET_PROTOTYPE_METHOD(t,
|
NODE_SET_PROTOTYPE_METHOD(t,
|
||||||
"restartHangMonitorTimeout",
|
"restartHangMonitorTimeout",
|
||||||
RestartHangMonitorTimeout);
|
RestartHangMonitorTimeout);
|
||||||
|
NODE_SET_PROTOTYPE_METHOD(t, "capturePage", CapturePage);
|
||||||
|
|
||||||
NODE_SET_PROTOTYPE_METHOD(t, "getPageTitle", GetPageTitle);
|
NODE_SET_PROTOTYPE_METHOD(t, "getPageTitle", GetPageTitle);
|
||||||
NODE_SET_PROTOTYPE_METHOD(t, "isLoading", IsLoading);
|
NODE_SET_PROTOTYPE_METHOD(t, "isLoading", IsLoading);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
||||||
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "base/memory/scoped_ptr.h"
|
#include "base/memory/scoped_ptr.h"
|
||||||
#include "browser/api/atom_api_event_emitter.h"
|
#include "browser/api/atom_api_event_emitter.h"
|
||||||
#include "browser/native_window_observer.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> IsWebViewFocused(const v8::Arguments& args);
|
||||||
static v8::Handle<v8::Value> RestartHangMonitorTimeout(
|
static v8::Handle<v8::Value> RestartHangMonitorTimeout(
|
||||||
const v8::Arguments &args);
|
const v8::Arguments &args);
|
||||||
|
static v8::Handle<v8::Value> CapturePage(const v8::Arguments& args);
|
||||||
|
|
||||||
// APIs for WebContents.
|
// APIs for WebContents.
|
||||||
static v8::Handle<v8::Value> GetPageTitle(const v8::Arguments &args);
|
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> Reload(const v8::Arguments &args);
|
||||||
static v8::Handle<v8::Value> ReloadIgnoringCache(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_;
|
scoped_ptr<NativeWindow> window_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Window);
|
DISALLOW_COPY_AND_ASSIGN(Window);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "common/api/api_messages.h"
|
#include "common/api/api_messages.h"
|
||||||
#include "common/options_switches.h"
|
#include "common/options_switches.h"
|
||||||
#include "ipc/ipc_message_macros.h"
|
#include "ipc/ipc_message_macros.h"
|
||||||
|
#include "ui/gfx/codec/png_codec.h"
|
||||||
#include "ui/gfx/point.h"
|
#include "ui/gfx/point.h"
|
||||||
#include "ui/gfx/rect.h"
|
#include "ui/gfx/rect.h"
|
||||||
#include "ui/gfx/size.h"
|
#include "ui/gfx/size.h"
|
||||||
|
@ -198,6 +199,16 @@ bool NativeWindow::SetIcon(const std::string& str_path) {
|
||||||
return true;
|
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() {
|
void NativeWindow::CloseWebContents() {
|
||||||
bool prevent_default = false;
|
bool prevent_default = false;
|
||||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
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,
|
void NativeWindow::OnRendererMessage(const string16& channel,
|
||||||
const base::ListValue& args) {
|
const base::ListValue& args) {
|
||||||
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
|
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
|
||||||
|
|
|
@ -49,6 +49,9 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||||
public content::WebContentsObserver,
|
public content::WebContentsObserver,
|
||||||
public content::NotificationObserver {
|
public content::NotificationObserver {
|
||||||
public:
|
public:
|
||||||
|
typedef base::Callback<void(const std::vector<unsigned char>& buffer)>
|
||||||
|
CapturePageCallback;
|
||||||
|
|
||||||
virtual ~NativeWindow();
|
virtual ~NativeWindow();
|
||||||
|
|
||||||
// Create window with existing WebContents.
|
// Create window with existing WebContents.
|
||||||
|
@ -108,6 +111,11 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||||
virtual void RestartHangMonitorTimeout();
|
virtual void RestartHangMonitorTimeout();
|
||||||
virtual bool SetIcon(const std::string& path);
|
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.
|
// The same with closing a tab in a real browser.
|
||||||
//
|
//
|
||||||
// Should be called by platform code when user want to close the window.
|
// Should be called by platform code when user want to close the window.
|
||||||
|
@ -184,6 +192,11 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||||
private:
|
private:
|
||||||
void RendererUnresponsiveDelayed();
|
void RendererUnresponsiveDelayed();
|
||||||
|
|
||||||
|
// Called when CapturePage has done.
|
||||||
|
void OnCapturePageDone(const CapturePageCallback& callback,
|
||||||
|
bool succeed,
|
||||||
|
const SkBitmap& bitmap);
|
||||||
|
|
||||||
void OnRendererMessage(const string16& channel,
|
void OnRendererMessage(const string16& channel,
|
||||||
const base::ListValue& args);
|
const base::ListValue& args);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
#include "base/string16.h"
|
#include "base/string16.h"
|
||||||
#include "browser/api/atom_api_window.h"
|
#include "browser/api/atom_api_window.h"
|
||||||
|
#include "ui/gfx/rect.h"
|
||||||
#include "v8/include/v8.h"
|
#include "v8/include/v8.h"
|
||||||
|
|
||||||
// Convert V8 value to arbitrary supported types.
|
// Convert V8 value to arbitrary supported types.
|
||||||
|
@ -38,6 +39,20 @@ struct FromV8Value {
|
||||||
return base::FilePath::FromUTF8Unsafe(FromV8Value(value_));
|
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>() {
|
operator std::vector<std::string>() {
|
||||||
std::vector<std::string> array;
|
std::vector<std::string> array;
|
||||||
v8::Handle<v8::Array> v8_array = v8::Handle<v8::Array>::Cast(value_);
|
v8::Handle<v8::Array> v8_array = v8::Handle<v8::Array>::Cast(value_);
|
||||||
|
@ -58,11 +73,9 @@ struct FromV8Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
operator v8::Persistent<v8::Function>() {
|
operator v8::Persistent<v8::Function>() {
|
||||||
return value_->IsFunction() ?
|
return v8::Persistent<v8::Function>::New(
|
||||||
v8::Persistent<v8::Function>::New(
|
node::node_isolate,
|
||||||
node::node_isolate,
|
v8::Handle<v8::Function>::Cast(value_));
|
||||||
v8::Handle<v8::Function>::Cast(value_)) :
|
|
||||||
v8::Persistent<v8::Function>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Handle<v8::Value> value_;
|
v8::Handle<v8::Value> value_;
|
||||||
|
@ -137,6 +150,11 @@ bool V8ValueCanBeConvertedTo<base::FilePath>(v8::Handle<v8::Value> value) {
|
||||||
return V8ValueCanBeConvertedTo<std::string>(value);
|
return V8ValueCanBeConvertedTo<std::string>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<> inline
|
||||||
|
bool V8ValueCanBeConvertedTo<gfx::Rect>(v8::Handle<v8::Value> value) {
|
||||||
|
return value->IsObject();
|
||||||
|
}
|
||||||
|
|
||||||
template<> inline
|
template<> inline
|
||||||
bool V8ValueCanBeConvertedTo<std::vector<std::string>>(
|
bool V8ValueCanBeConvertedTo<std::vector<std::string>>(
|
||||||
v8::Handle<v8::Value> value) {
|
v8::Handle<v8::Value> value) {
|
||||||
|
|
|
@ -290,6 +290,23 @@ Starts inspecting element at position (`x`, `y`).
|
||||||
|
|
||||||
### BrowserWindow.restartHangMonitorTimeout()
|
### 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()
|
### BrowserWindow.getPageTitle()
|
||||||
|
|
||||||
Returns the title of web page.
|
Returns the title of web page.
|
||||||
|
|
|
@ -75,6 +75,13 @@ describe 'window module', ->
|
||||||
assert.equal w.isVisible(), false
|
assert.equal w.isVisible(), false
|
||||||
w.close()
|
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', ->
|
describe 'beforeunload handler', ->
|
||||||
it 'returning true would not prevent close', (done) ->
|
it 'returning true would not prevent close', (done) ->
|
||||||
w = new BrowserWindow(show: false)
|
w = new BrowserWindow(show: false)
|
||||||
|
|
2
vendor/node
vendored
2
vendor/node
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 7f44fac0fd64af7ec172c9606af1f3cec684a9ce
|
Subproject commit 24c11bdc794c2b7b79163cb4737046f8de42446d
|
Loading…
Add table
Add a link
Reference in a new issue