Commit e1879b6e authored by Mason Freed's avatar Mason Freed Committed by Commit Bot

[CI] Adding functionality to RenderWidgetHostViewAura::CopyFromSurface to capture popups.

Previous to this CL, the RenderWidgetHostViewAura::CopyFromSurface function would capture
only the main window contents. It would ignore any secondary child popup screens that
were generated as a result of many popup operations, for example calendar pickers, selection popups,
suggestion pickers, etc. With this CL, those popup screens are detected, captured, and
overlaid on top of the main window capture.

Note that in the process of implementing this, I fixed a bug in
RenderWidgetHostViewAura::GetBoundsInRootWindow(), for the Windows case. Previous to this CL,
for Windows, when legacy HWNDs are not in use (UsesNativeWindowFrame() returns false), the
function would return locations in units of DIPs divided by scale factor. It should be returning
DIPs. I moved the conversion up into the if{} block. It seems that no current test catches this
issue, but once --enable-display-compositor-pixel-dumps becomes a default flag, the existing
layout tests, under virtual/scalefactorXyz, should serve to monitor this code for regressions.

Bug: 875962, 667551

Change-Id: Iefc9bfd7798b3dfabb3a28eb46009fa703c0fca0
Reviewed-on: https://chromium-review.googlesource.com/1192330
Commit-Queue: Mason Freed <masonfreed@chromium.org>
Reviewed-by: default avatarFady Samuel <fsamuel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#589975}
parent 3e1d472b
......@@ -45,7 +45,8 @@ DelegatedFrameHost::DelegatedFrameHost(const viz::FrameSinkId& frame_sink_id,
base::FeatureList::IsEnabled(features::kVizDisplayCompositor)),
should_register_frame_sink_id_(should_register_frame_sink_id),
host_frame_sink_manager_(GetHostFrameSinkManager()),
frame_evictor_(std::make_unique<viz::FrameEvictor>(this)) {
frame_evictor_(std::make_unique<viz::FrameEvictor>(this)),
weak_factory_(this) {
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
factory->GetContextFactory()->AddObserver(this);
DCHECK(host_frame_sink_manager_);
......
......@@ -10,6 +10,7 @@
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "components/viz/client/frame_evictor.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
......@@ -179,6 +180,10 @@ class CONTENT_EXPORT DelegatedFrameHost
// |other|.
void TakeFallbackContentFrom(DelegatedFrameHost* other);
base::WeakPtr<DelegatedFrameHost> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
friend class DelegatedFrameHostClient;
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
......@@ -242,6 +247,8 @@ class CONTENT_EXPORT DelegatedFrameHost
std::vector<std::unique_ptr<viz::CopyOutputRequest>>
pending_first_frame_requests_;
base::WeakPtrFactory<DelegatedFrameHost> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DelegatedFrameHost);
};
......
......@@ -840,8 +840,17 @@ void RenderWidgetHostViewAura::CopyFromSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
base::OnceCallback<void(const SkBitmap&)> callback) {
delegated_frame_host_->CopyFromCompositingSurface(src_subrect, dst_size,
std::move(callback));
base::WeakPtr<RenderWidgetHostImpl> popup_host;
base::WeakPtr<DelegatedFrameHost> popup_frame_host;
if (popup_child_host_view_) {
popup_host = popup_child_host_view_->host()->GetWeakPtr();
popup_frame_host =
popup_child_host_view_->GetDelegatedFrameHost()->GetWeakPtr();
}
RenderWidgetHostViewBase::CopyMainAndPopupFromSurface(
host()->GetWeakPtr(), delegated_frame_host_->GetWeakPtr(), popup_host,
popup_frame_host, src_subrect, dst_size, device_scale_factor_,
std::move(callback));
}
#if defined(OS_WIN)
......@@ -943,10 +952,13 @@ gfx::Rect RenderWidgetHostViewAura::GetBoundsInRootWindow() {
bounds.Inset(GetSystemMetrics(SM_CXPADDEDBORDER),
GetSystemMetrics(SM_CXPADDEDBORDER));
}
// Pixels come back from GetWindowHost, so we need to convert those back to
// DIPs here.
bounds = display::Screen::GetScreen()->ScreenToDIPRectInWindow(top_level,
bounds);
}
bounds =
display::Screen::GetScreen()->ScreenToDIPRectInWindow(top_level, bounds);
#endif
return bounds;
......@@ -1906,12 +1918,12 @@ RenderWidgetHostViewAura::~RenderWidgetHostViewAura() {
DetachFromInputMethod();
}
if (popup_parent_host_view_) {
DCHECK(popup_parent_host_view_->popup_child_host_view_ == nullptr ||
DCHECK(!popup_parent_host_view_->popup_child_host_view_ ||
popup_parent_host_view_->popup_child_host_view_ == this);
popup_parent_host_view_->SetPopupChild(nullptr);
}
if (popup_child_host_view_) {
DCHECK(popup_child_host_view_->popup_parent_host_view_ == nullptr ||
DCHECK(!popup_child_host_view_->popup_parent_host_view_ ||
popup_child_host_view_->popup_parent_host_view_ == this);
popup_child_host_view_->popup_parent_host_view_ = nullptr;
}
......
......@@ -16,6 +16,7 @@
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/frame_host/render_widget_host_view_guest.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/renderer_host/delegated_frame_host.h"
#include "content/browser/renderer_host/display_util.h"
#include "content/browser/renderer_host/input/mouse_wheel_phase_handler.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
......@@ -203,6 +204,87 @@ bool RenderWidgetHostViewBase::IsSurfaceAvailableForCopy() const {
return false;
}
void RenderWidgetHostViewBase::CopyMainAndPopupFromSurface(
base::WeakPtr<RenderWidgetHostImpl> main_host,
base::WeakPtr<DelegatedFrameHost> main_frame_host,
base::WeakPtr<RenderWidgetHostImpl> popup_host,
base::WeakPtr<DelegatedFrameHost> popup_frame_host,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
float scale_factor,
base::OnceCallback<void(const SkBitmap&)> callback) {
if (!main_host || !main_frame_host)
return;
#if defined(OS_ANDROID)
NOTREACHED()
<< "RenderWidgetHostViewAndroid::CopyFromSurface calls "
"DelegatedFrameHostAndroid::CopyFromCompositingSurface directly, "
"and popups are not supported.";
return;
#else
if (!popup_host || !popup_frame_host) {
// No popup - just call CopyFromCompositingSurface once.
main_frame_host->CopyFromCompositingSurface(src_subrect, dst_size,
std::move(callback));
return;
}
// First locate the popup relative to the main page, in DIPs
const gfx::Point parent_location =
main_host->GetView()->GetBoundsInRootWindow().origin();
const gfx::Point popup_location =
popup_host->GetView()->GetBoundsInRootWindow().origin();
const gfx::Point offset_dips =
PointAtOffsetFromOrigin(popup_location - parent_location);
const gfx::Vector2d offset_physical =
ScaleToFlooredPoint(offset_dips, scale_factor).OffsetFromOrigin();
// Queue up the request for the MAIN frame image first, but with a
// callback that launches a second request for the popup image.
// 1. Call CopyFromCompositingSurface for the main frame, with callback
// |main_image_done_callback|. Inside |main_image_done_callback|:
// a. Call CopyFromCompositingSurface again, this time on the popup
// frame. For this call, build a new callback, |popup_done_callback|,
// which:
// i. Takes the main image as a parameter, combines the main image with
// the just-acquired popup image, and then calls the original
// (outer) callback with the combined image.
auto main_image_done_callback = base::BindOnce(
[](base::OnceCallback<void(const SkBitmap&)> final_callback,
const gfx::Vector2d offset,
base::WeakPtr<DelegatedFrameHost> popup_frame_host,
const gfx::Rect src_subrect, const gfx::Size dst_size,
const SkBitmap& main_image) {
if (!popup_frame_host)
return;
// Build a new callback that actually combines images.
auto popup_done_callback = base::BindOnce(
[](base::OnceCallback<void(const SkBitmap&)> final_callback,
const gfx::Vector2d offset, const SkBitmap& main_image,
const SkBitmap& popup_image) {
// Draw popup_image into main_image.
SkCanvas canvas(main_image);
canvas.drawBitmap(popup_image, offset.x(), offset.y());
std::move(final_callback).Run(main_image);
},
std::move(final_callback), offset, std::move(main_image));
// Second, request the popup image.
gfx::Rect popup_subrect(src_subrect - offset);
popup_frame_host->CopyFromCompositingSurface(
popup_subrect, dst_size, std::move(popup_done_callback));
},
std::move(callback), offset_physical, popup_frame_host, src_subrect,
dst_size);
// Request the main image (happens first).
main_frame_host->CopyFromCompositingSurface(
src_subrect, dst_size, std::move(main_image_done_callback));
#endif
}
void RenderWidgetHostViewBase::CopyFromSurface(
const gfx::Rect& src_rect,
const gfx::Size& output_size,
......
......@@ -88,6 +88,7 @@ class TextInputManager;
class TouchSelectionControllerClientManager;
class WebContentsAccessibility;
class WebCursor;
class DelegatedFrameHost;
struct TextInputState;
// Basic implementation shared by concrete RenderWidgetHostView subclasses.
......@@ -162,6 +163,16 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
void OnLocalSurfaceIdChanged(
const cc::RenderFrameMetadata& metadata) override;
static void CopyMainAndPopupFromSurface(
base::WeakPtr<RenderWidgetHostImpl> main_host,
base::WeakPtr<DelegatedFrameHost> main_frame_host,
base::WeakPtr<RenderWidgetHostImpl> popup_host,
base::WeakPtr<DelegatedFrameHost> popup_frame_host,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
float scale_factor,
base::OnceCallback<void(const SkBitmap&)> callback);
void SetPopupType(blink::WebPopupType popup_type);
blink::WebPopupType GetPopupType();
......
......@@ -535,6 +535,12 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// RenderWidgetHostViewGuest.
bool is_guest_view_hack_;
// Our parent host view, if this is a popup. NULL otherwise.
RenderWidgetHostViewMac* popup_parent_host_view_;
// Our child popup host. NULL if we do not have a child popup.
RenderWidgetHostViewMac* popup_child_host_view_;
// Display link for getting vsync info.
scoped_refptr<ui::DisplayLinkMac> display_link_;
......
......@@ -148,6 +148,8 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget,
mouse_wheel_phase_handler_(this),
is_loading_(false),
is_guest_view_hack_(is_guest_view_hack),
popup_parent_host_view_(nullptr),
popup_child_host_view_(nullptr),
gesture_provider_(ui::GetGestureProviderConfig(
ui::GestureProviderConfigType::CURRENT_PLATFORM),
this),
......@@ -213,6 +215,16 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget,
RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
if (features::IsViewsBrowserCocoa())
ui::CATransactionCoordinator::Get().RemovePreCommitObserver(this);
if (popup_parent_host_view_) {
DCHECK(!popup_parent_host_view_->popup_child_host_view_ ||
popup_parent_host_view_->popup_child_host_view_ == this);
popup_parent_host_view_->popup_child_host_view_ = nullptr;
}
if (popup_child_host_view_) {
DCHECK(!popup_child_host_view_->popup_parent_host_view_ ||
popup_child_host_view_->popup_parent_host_view_ == this);
popup_child_host_view_->popup_parent_host_view_ = nullptr;
}
}
void RenderWidgetHostViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) {
......@@ -279,6 +291,17 @@ void RenderWidgetHostViewMac::InitAsChild(
void RenderWidgetHostViewMac::InitAsPopup(
RenderWidgetHostView* parent_host_view,
const gfx::Rect& pos) {
popup_parent_host_view_ =
static_cast<RenderWidgetHostViewMac*>(parent_host_view);
RenderWidgetHostViewMac* old_child =
popup_parent_host_view_->popup_child_host_view_;
if (old_child) {
DCHECK(old_child->popup_parent_host_view_ == popup_parent_host_view_);
old_child->popup_parent_host_view_ = nullptr;
}
popup_parent_host_view_->popup_child_host_view_ = this;
// This path is used by the time/date picker.
ns_view_bridge_->InitAsPopup(pos, popup_type_);
}
......@@ -776,8 +799,19 @@ void RenderWidgetHostViewMac::CopyFromSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
base::OnceCallback<void(const SkBitmap&)> callback) {
browser_compositor_->GetDelegatedFrameHost()->CopyFromCompositingSurface(
src_subrect, dst_size, std::move(callback));
base::WeakPtr<RenderWidgetHostImpl> popup_host;
base::WeakPtr<DelegatedFrameHost> popup_frame_host;
if (popup_child_host_view_) {
popup_host = popup_child_host_view_->host()->GetWeakPtr();
popup_frame_host = popup_child_host_view_->BrowserCompositor()
->GetDelegatedFrameHost()
->GetWeakPtr();
}
RenderWidgetHostViewBase::CopyMainAndPopupFromSurface(
host()->GetWeakPtr(),
browser_compositor_->GetDelegatedFrameHost()->GetWeakPtr(), popup_host,
popup_frame_host, src_subrect, dst_size, display_.device_scale_factor(),
std::move(callback));
}
void RenderWidgetHostViewMac::EnsureSurfaceSynchronizedForLayoutTest() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment