2015-09-18 07:57:43 +00:00
|
|
|
// Copyright (c) 2015 GitHub, Inc.
|
|
|
|
// Use of this source code is governed by the MIT license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "atom/browser/api/frame_subscriber.h"
|
|
|
|
|
2016-06-21 00:15:39 +00:00
|
|
|
#include "atom/common/native_mate_converters/gfx_converter.h"
|
2018-05-14 15:55:39 +00:00
|
|
|
#include "components/viz/common/frame_sinks/copy_output_request.h"
|
|
|
|
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
|
|
|
|
#include "components/viz/service/surfaces/surface_manager.h"
|
2018-04-18 00:45:15 +00:00
|
|
|
#include "content/browser/compositor/surface_utils.h"
|
|
|
|
#include "content/browser/renderer_host/render_widget_host_view_base.h"
|
2018-05-14 15:55:39 +00:00
|
|
|
#include "ui/gfx/geometry/rect_conversions.h"
|
2018-05-14 17:09:05 +00:00
|
|
|
#include "ui/gfx/skbitmap_operations.h"
|
2016-09-06 08:24:37 +00:00
|
|
|
|
2018-06-19 17:49:44 +00:00
|
|
|
#include "atom/common/node_includes.h"
|
|
|
|
|
2015-09-18 07:57:43 +00:00
|
|
|
namespace atom {
|
|
|
|
|
|
|
|
namespace api {
|
|
|
|
|
|
|
|
FrameSubscriber::FrameSubscriber(v8::Isolate* isolate,
|
2018-05-14 15:55:39 +00:00
|
|
|
content::WebContents* web_contents,
|
2018-05-14 17:09:05 +00:00
|
|
|
const FrameCaptureCallback& callback,
|
|
|
|
bool only_dirty)
|
2018-05-14 15:55:39 +00:00
|
|
|
: content::WebContentsObserver(web_contents),
|
|
|
|
isolate_(isolate),
|
2018-05-14 17:09:05 +00:00
|
|
|
callback_(callback),
|
|
|
|
only_dirty_(only_dirty) {}
|
2017-04-13 10:21:30 +00:00
|
|
|
|
2018-04-18 00:45:15 +00:00
|
|
|
FrameSubscriber::~FrameSubscriber() = default;
|
2015-09-18 07:57:43 +00:00
|
|
|
|
2018-05-14 15:55:39 +00:00
|
|
|
gfx::Rect FrameSubscriber::GetDamageRect() {
|
|
|
|
auto* view = web_contents()->GetRenderWidgetHostView();
|
|
|
|
if (view == nullptr)
|
|
|
|
return gfx::Rect();
|
|
|
|
|
|
|
|
auto* view_base = static_cast<content::RenderWidgetHostViewBase*>(view);
|
|
|
|
viz::SurfaceManager* surface_manager =
|
|
|
|
content::GetFrameSinkManager()->surface_manager();
|
|
|
|
viz::Surface* surface =
|
|
|
|
surface_manager->GetSurfaceForId(view_base->GetCurrentSurfaceId());
|
|
|
|
if (surface == nullptr)
|
|
|
|
return gfx::Rect();
|
|
|
|
|
|
|
|
if (surface->HasActiveFrame()) {
|
|
|
|
const viz::CompositorFrame& frame = surface->GetActiveFrame();
|
|
|
|
viz::RenderPass* root_pass = frame.render_pass_list.back().get();
|
|
|
|
gfx::Size frame_size = root_pass->output_rect.size();
|
|
|
|
gfx::Rect damage_rect =
|
|
|
|
gfx::ToEnclosingRect(gfx::RectF(root_pass->damage_rect));
|
|
|
|
damage_rect.Intersect(gfx::Rect(frame_size));
|
|
|
|
return gfx::ScaleToEnclosedRect(damage_rect,
|
|
|
|
1.0f / frame.device_scale_factor());
|
|
|
|
} else {
|
|
|
|
return gfx::Rect();
|
2018-04-18 00:45:15 +00:00
|
|
|
}
|
2018-05-14 15:55:39 +00:00
|
|
|
}
|
2017-07-28 09:57:41 +00:00
|
|
|
|
2018-05-14 15:55:39 +00:00
|
|
|
void FrameSubscriber::DidReceiveCompositorFrame() {
|
|
|
|
auto* view = web_contents()->GetRenderWidgetHostView();
|
|
|
|
if (view == nullptr)
|
2015-09-18 07:57:43 +00:00
|
|
|
return;
|
|
|
|
|
2018-05-14 15:55:39 +00:00
|
|
|
view->CopyFromSurface(
|
|
|
|
gfx::Rect(), view->GetViewBounds().size(),
|
|
|
|
base::BindOnce(&FrameSubscriber::Done, base::Unretained(this),
|
|
|
|
GetDamageRect()));
|
2018-04-18 00:45:15 +00:00
|
|
|
}
|
|
|
|
|
2018-05-14 15:55:39 +00:00
|
|
|
void FrameSubscriber::Done(const gfx::Rect& damage, const SkBitmap& frame) {
|
|
|
|
if (frame.drawsNothing())
|
|
|
|
return;
|
2018-04-18 00:45:15 +00:00
|
|
|
|
2018-06-19 17:49:44 +00:00
|
|
|
v8::Locker locker(isolate_);
|
|
|
|
v8::HandleScope handle_scope(isolate_);
|
|
|
|
|
2018-05-14 15:55:39 +00:00
|
|
|
const_cast<SkBitmap&>(frame).setAlphaType(kPremul_SkAlphaType);
|
2018-06-19 17:49:44 +00:00
|
|
|
const SkBitmap& bitmap = only_dirty_ ? SkBitmapOperations::CreateTiledBitmap(
|
|
|
|
frame, damage.x(), damage.y(),
|
|
|
|
damage.width(), damage.height())
|
|
|
|
: frame;
|
|
|
|
|
|
|
|
size_t rgb_row_size = bitmap.width() * bitmap.bytesPerPixel();
|
2018-06-20 19:51:36 +00:00
|
|
|
auto* source = static_cast<const char*>(bitmap.getPixels());
|
2018-06-19 17:49:44 +00:00
|
|
|
|
|
|
|
v8::MaybeLocal<v8::Object> buffer =
|
|
|
|
node::Buffer::Copy(isolate_, source, rgb_row_size * bitmap.height());
|
|
|
|
auto local_buffer = buffer.ToLocalChecked();
|
|
|
|
|
2018-05-14 15:55:39 +00:00
|
|
|
v8::Local<v8::Value> damage_rect =
|
|
|
|
mate::Converter<gfx::Rect>::ToV8(isolate_, damage);
|
2018-05-14 17:09:05 +00:00
|
|
|
|
2018-06-19 17:49:44 +00:00
|
|
|
callback_.Run(local_buffer, damage_rect);
|
2015-09-18 07:57:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace api
|
|
|
|
|
|
|
|
} // namespace atom
|