Commit 27891f21 authored by Songtao Xia's avatar Songtao Xia Committed by Commit Bot

[DevTools] cdp support for multisegments feature in platform

This is to add cdp support for the frontend to send window segments
info to the backend, to be consumed by the platform.

The explainer for window segments is at:
Explainer:  https://github.com/webscreens/window-segments/blob/master/EXPLAINER.md

During discussion of the dual screen explainer, it was agreed that the
change will be reviewed at CR time. The explainer is at:
https://docs.google.com/document/d/1KMsmEXdjmn4h4iIl0n74N1EHxwwNUzh6R2p7GHrdtTI/

This change can be tested with web_tests. But it relies on a frontend
CL and one more platform CL for a user to see the effect. The frontend
CL (WIP) is at:
https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2245774

The platform CL:

https://chromium-review.googlesource.com/c/chromium/src/+/2262193

Change-Id: I6309b8bea0b24b0d098a82a02045115f00d2b34f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2248131Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Reviewed-by: default avatarWill Harris <wfh@chromium.org>
Reviewed-by: default avatarSigurd Schneider <sigurds@chromium.org>
Commit-Queue: Songtao Xia <soxia@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#786932}
parent 3806318d
......@@ -41,6 +41,15 @@ blink::WebScreenOrientationType WebScreenOrientationTypeFromString(
return blink::kWebScreenOrientationUndefined;
}
base::Optional<content::DisplayFeature::Orientation>
DisplayFeatureOrientationTypeFromString(const std::string& type) {
if (type == Emulation::DisplayFeature::OrientationEnum::Vertical)
return content::DisplayFeature::Orientation::kVertical;
if (type == Emulation::DisplayFeature::OrientationEnum::Horizontal)
return content::DisplayFeature::Orientation::kHorizontal;
return base::nullopt;
}
ui::GestureProviderConfigType TouchEmulationConfigurationToType(
const std::string& protocol_value) {
ui::GestureProviderConfigType result =
......@@ -182,7 +191,8 @@ Response EmulationHandler::SetDeviceMetricsOverride(
Maybe<int> position_y,
Maybe<bool> dont_set_visible_size,
Maybe<Emulation::ScreenOrientation> screen_orientation,
Maybe<protocol::Page::Viewport> viewport) {
Maybe<protocol::Page::Viewport> viewport,
Maybe<protocol::Emulation::DisplayFeature> displayFeature) {
const static int max_size = 10000000;
const static double max_scale = 10;
const static int max_orientation_angle = 360;
......@@ -235,6 +245,41 @@ Response EmulationHandler::SetDeviceMetricsOverride(
}
}
base::Optional<content::DisplayFeature> display_feature = base::nullopt;
if (displayFeature.isJust()) {
protocol::Emulation::DisplayFeature* emu_display_feature =
displayFeature.fromJust();
base::Optional<content::DisplayFeature::Orientation> disp_orientation =
DisplayFeatureOrientationTypeFromString(
emu_display_feature->GetOrientation());
if (!disp_orientation) {
return Response::InvalidParams(
"Invalid display feature orientation type");
}
content::DisplayFeature::ParamErrorEnum error;
display_feature = content::DisplayFeature::Create(
*disp_orientation, emu_display_feature->GetOffset(),
emu_display_feature->GetMaskLength(), width, height, &error);
if (!display_feature) {
switch (error) {
case content::DisplayFeature::ParamErrorEnum::
kDisplayFeatureWithZeroScreenSize:
return Response::InvalidParams(
"Cannot specify a display feature with zero width and height");
case content::DisplayFeature::ParamErrorEnum::
kNegativeDisplayFeatureParams:
return Response::InvalidParams("Negative display feature parameters");
case content::DisplayFeature::ParamErrorEnum::kOutsideScreenWidth:
return Response::InvalidParams(
"Display feature window segments outside screen width");
case content::DisplayFeature::ParamErrorEnum::kOutsideScreenHeight:
return Response::InvalidParams(
"Display feature window segments outside screen height");
}
}
}
blink::WebDeviceEmulationParams params;
params.screen_position = mobile ? blink::WebDeviceEmulationParams::kMobile
: blink::WebDeviceEmulationParams::kDesktop;
......@@ -250,6 +295,11 @@ Response EmulationHandler::SetDeviceMetricsOverride(
params.screen_orientation_type = orientationType;
params.screen_orientation_angle = orientationAngle;
if (display_feature) {
params.window_segments =
display_feature->ComputeWindowSegments(params.view_size);
}
if (viewport.isJust()) {
params.viewport_offset.SetPoint(viewport.fromJust()->GetX(),
viewport.fromJust()->GetY());
......
......@@ -67,7 +67,8 @@ class EmulationHandler : public DevToolsDomainHandler,
Maybe<int> position_y,
Maybe<bool> dont_set_visible_size,
Maybe<Emulation::ScreenOrientation> screen_orientation,
Maybe<protocol::Page::Viewport> viewport) override;
Maybe<protocol::Page::Viewport> viewport,
Maybe<protocol::Emulation::DisplayFeature> displayFeature) override;
Response ClearDeviceMetricsOverride() override;
Response SetVisibleSize(int width, int height) override;
......
......@@ -15,4 +15,63 @@ bool DisplayFeature::operator!=(const DisplayFeature& other) const {
return !(*this == other);
}
std::vector<gfx::Rect> DisplayFeature::ComputeWindowSegments(
const gfx::Size& visible_viewport_size) const {
std::vector<gfx::Rect> window_segments;
int display_feature_end = offset + mask_length;
if (orientation == DisplayFeature::Orientation::kVertical) {
// If the display feature is vertically oriented, it splits or masks
// the widget into two side-by-side segments. Note that in the masking
// scenario, there is an area of the widget that are not covered by the
// union of the window segments - this area's pixels will not be visible
// to the user.
window_segments.emplace_back(0, 0, offset, visible_viewport_size.height());
window_segments.emplace_back(
display_feature_end, 0,
visible_viewport_size.width() - display_feature_end,
visible_viewport_size.height());
} else {
// If the display feature is offset in the y direction, it splits or masks
// the widget into two stacked segments.
window_segments.emplace_back(0, 0, visible_viewport_size.width(), offset);
window_segments.emplace_back(
0, display_feature_end, visible_viewport_size.width(),
visible_viewport_size.height() - display_feature_end);
}
return window_segments;
}
// static
base::Optional<DisplayFeature> DisplayFeature::Create(Orientation orientation,
int offset,
int mask_length,
int width,
int height,
ParamErrorEnum* error) {
if (!width && !height) {
*error = ParamErrorEnum::kDisplayFeatureWithZeroScreenSize;
return base::nullopt;
}
if (offset < 0 || mask_length < 0) {
*error = ParamErrorEnum::kNegativeDisplayFeatureParams;
return base::nullopt;
}
if (orientation == Orientation::kVertical && offset + mask_length > width) {
*error = ParamErrorEnum::kOutsideScreenWidth;
return base::nullopt;
}
if (orientation == Orientation::kHorizontal &&
offset + mask_length > height) {
*error = ParamErrorEnum::kOutsideScreenHeight;
return base::nullopt;
}
return DisplayFeature{orientation, offset, mask_length};
}
} // namespace content
......@@ -5,8 +5,10 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_DISPLAY_FEATURE_H_
#define CONTENT_BROWSER_RENDERER_HOST_DISPLAY_FEATURE_H_
#include "base/optional.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
#include "ui/gfx/geometry/rect.h"
namespace content {
......@@ -33,6 +35,12 @@ namespace content {
// the screen on which it exists.
struct CONTENT_EXPORT DisplayFeature {
enum class Orientation { kVertical, kHorizontal, kMaxValue = kHorizontal };
enum class ParamErrorEnum {
kDisplayFeatureWithZeroScreenSize = 1,
kNegativeDisplayFeatureParams,
kOutsideScreenWidth,
kOutsideScreenHeight
};
// The orientation of the display feature in relation to the screen.
Orientation orientation = Orientation::kVertical;
......@@ -48,6 +56,20 @@ struct CONTENT_EXPORT DisplayFeature {
bool operator==(const DisplayFeature& other) const;
bool operator!=(const DisplayFeature& other) const;
// Computes logical segments of the |visible_viewport_size|, based on
// this display feature. These segments are in DIPs relative to the widget
// origin.
std::vector<gfx::Rect> ComputeWindowSegments(
const gfx::Size& visible_viewport_size) const;
static base::Optional<DisplayFeature> Create(
Orientation orientation,
int offset,
int mask_length,
int screen_width,
int screen_height,
DisplayFeature::ParamErrorEnum* error);
};
} // namespace content
......
......@@ -935,8 +935,14 @@ VisualProperties RenderWidgetHostImpl::GetVisualProperties() {
// use the value provided from the parent.
if (is_top_most_widget) {
const DisplayFeature* display_feature = view_->GetDisplayFeature();
visual_properties.root_widget_window_segments = ComputeRootWindowSegments(
visual_properties.visible_viewport_size, display_feature);
if (display_feature) {
visual_properties.root_widget_window_segments =
display_feature->ComputeWindowSegments(
visual_properties.visible_viewport_size);
} else {
visual_properties.root_widget_window_segments = {
gfx::Rect(visual_properties.visible_viewport_size)};
}
} else {
visual_properties.root_widget_window_segments =
properties_from_parent_local_root_.root_widget_window_segments;
......@@ -1064,43 +1070,6 @@ bool RenderWidgetHostImpl::SynchronizeVisualProperties(
return true;
}
std::vector<gfx::Rect> RenderWidgetHostImpl::ComputeRootWindowSegments(
const gfx::Size& visible_viewport_size,
const DisplayFeature* display_feature) const {
std::vector<gfx::Rect> window_segments;
if (!display_feature) {
window_segments.emplace_back(visible_viewport_size);
return window_segments;
}
int display_feature_end =
display_feature->offset + display_feature->mask_length;
if (display_feature->orientation == DisplayFeature::Orientation::kVertical) {
// If the display feature is vertically oriented, it splits or masks
// the widget into two side-by-side segments. Note that in the masking
// scenario, there is an area of the widget that are not covered by the
// union of the window segments - this area's pixels will not be visible
// to the user.
window_segments.emplace_back(0, 0, display_feature->offset,
visible_viewport_size.height());
window_segments.emplace_back(
display_feature_end, 0,
visible_viewport_size.width() - display_feature_end,
visible_viewport_size.height());
} else {
// If the display feature is offset in the y direction, it splits or masks
// the widget into two stacked segments.
window_segments.emplace_back(0, 0, visible_viewport_size.width(),
display_feature->offset);
window_segments.emplace_back(
0, display_feature_end, visible_viewport_size.width(),
visible_viewport_size.height() - display_feature_end);
}
return window_segments;
}
void RenderWidgetHostImpl::GotFocus() {
Focus();
if (owner_delegate_)
......
......@@ -105,7 +105,6 @@ class SyntheticGestureController;
class TimeoutMonitor;
class TouchEmulator;
class WebCursor;
struct DisplayFeature;
struct VisualProperties;
struct ScreenInfo;
......@@ -833,14 +832,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
bool IsMouseLocked() const;
// Computes logical segments of the |visible_viewport_size|, based on the
// optional DisplayFeature. These segments are in DIPs relative to the widget
// origin. If a DisplayFeature is not provided, a vector with a single rect,
// the size of the visible viewport will be returned.
std::vector<gfx::Rect> ComputeRootWindowSegments(
const gfx::Size& visible_viewport_size,
const DisplayFeature* display_feature) const;
// The View associated with the RenderWidgetHost. The lifetime of this object
// is associated with the lifetime of the Render process. If the Renderer
// crashes, its View is destroyed and this pointer becomes NULL, even though
......
......@@ -54,6 +54,7 @@ IPC_STRUCT_TRAITS_BEGIN(blink::WebDeviceEmulationParams)
IPC_STRUCT_TRAITS_MEMBER(viewport_scale)
IPC_STRUCT_TRAITS_MEMBER(screen_orientation_angle)
IPC_STRUCT_TRAITS_MEMBER(screen_orientation_type)
IPC_STRUCT_TRAITS_MEMBER(window_segments)
IPC_STRUCT_TRAITS_END()
//
......
......@@ -853,6 +853,9 @@ void RenderWidget::OnEnableDeviceEmulation(
window_screen_rect_);
}
device_emulator_->ChangeEmulationParams(params);
// TODO: crbug.com/1099026
// https://chromium-review.googlesource.com/c/chromium/src/+/2262193/1
// Update root_widget_window_segments here.
}
void RenderWidget::OnDisableDeviceEmulation() {
......
......@@ -2956,6 +2956,20 @@ domain Emulation
# Orientation angle.
integer angle
type DisplayFeature extends object
properties
# Orientation of a display feature in relation to screen
enum orientation
vertical
horizontal
# The offset from the screen origin in either the x (for vertical
# orientation) or y (for horizontal orientation) direction.
integer offset
# A display feature may mask content such that it is not physically
# displayed - this length along with the offset describes this area.
# A display feature that only splits content will have a 0 mask_length.
integer maskLength
type MediaFeature extends object
properties
string name
......@@ -3054,6 +3068,9 @@ domain Emulation
# If set, the visible area of the page will be overridden to this viewport. This viewport
# change is not observed by the page, e.g. viewport-relative elements do not change positions.
experimental optional Page.Viewport viewport
# If set, the display feature of a multi-segment screen. If not set, multi-segment support
# is turned-off.
experimental optional DisplayFeature displayFeature
experimental command setScrollbarsHidden
parameters
......
......@@ -55,6 +55,9 @@ struct WebDeviceEmulationParams {
// Screen orientation angle, used together with screenOrientationType.
int screen_orientation_angle;
// Screen window segments dimensions.
std::vector<gfx::Rect> window_segments;
WebDeviceEmulationParams()
: screen_position(kDesktop),
device_scale_factor(0),
......@@ -74,7 +77,8 @@ inline bool operator==(const WebDeviceEmulationParams& a,
a.screen_orientation_type == b.screen_orientation_type &&
a.screen_orientation_angle == b.screen_orientation_angle &&
a.viewport_offset == b.viewport_offset &&
a.viewport_scale == b.viewport_scale;
a.viewport_scale == b.viewport_scale &&
a.window_segments == b.window_segments;
}
inline bool operator!=(const WebDeviceEmulationParams& a,
......
......@@ -516,7 +516,8 @@ Response InspectorEmulationAgent::setDeviceMetricsOverride(
Maybe<int> position_y,
Maybe<bool> dont_set_visible_size,
Maybe<protocol::Emulation::ScreenOrientation>,
Maybe<protocol::Page::Viewport>) {
Maybe<protocol::Page::Viewport>,
Maybe<protocol::Emulation::DisplayFeature>) {
// We don't have to do anything other than reply to the client, as the
// emulation parameters should have already been updated by the handling of
// WidgetMsg_EnableDeviceEmulation.
......
......@@ -75,7 +75,8 @@ class CORE_EXPORT InspectorEmulationAgent final
protocol::Maybe<int> position_y,
protocol::Maybe<bool> dont_set_visible_size,
protocol::Maybe<protocol::Emulation::ScreenOrientation>,
protocol::Maybe<protocol::Page::Viewport>) override;
protocol::Maybe<protocol::Page::Viewport>,
protocol::Maybe<protocol::Emulation::DisplayFeature>) override;
protocol::Response clearDeviceMetricsOverride() override;
protocol::Response setUserAgentOverride(
const String& user_agent,
......
Tests emulation of the user agent.
{
id : <number>
result : {
}
sessionId : <string>
}
{
error : {
code : -32602
message : Cannot specify a display feature with zero width and height
}
id : <number>
sessionId : <string>
}
{
error : {
code : -32602
message : Negative display feature parameters
}
id : <number>
sessionId : <string>
}
{
error : {
code : -32602
message : Invalid display feature orientation type
}
id : <number>
sessionId : <string>
}
{
error : {
code : -32602
message : Display feature window segments outside screen width
}
id : <number>
sessionId : <string>
}
{
id : <number>
result : {
}
sessionId : <string>
}
{
error : {
code : -32602
message : Display feature window segments outside screen height
}
id : <number>
sessionId : <string>
}
(async function(testRunner) {
var {page, session, dp} =
await testRunner.startBlank('Tests emulation of the user agent.');
// vertical: ok
var response = await dp.Emulation.setDeviceMetricsOverride({
width: 100,
height: 200,
deviceScaleFactor: 2.5,
mobile: true,
scale: 1.2,
screenWidth: 100,
screenHeight: 200,
positionX: 0,
positionY: 0,
displayFeature: { orientation: 'vertical', offset: 30, maskLength: 20}
});
testRunner.log(response);
// invalid width and height
response = await dp.Emulation.setDeviceMetricsOverride({
width: 0,
height: 0,
deviceScaleFactor: 2.5,
mobile: true,
scale: 1.2,
screenWidth: 100,
screenHeight: 200,
positionX: 0,
positionY: 0,
displayFeature: { orientation: 'vertical', offset: 30, maskLength: 20}
});
testRunner.log(response);
// invalid display feature parameters.
response = await dp.Emulation.setDeviceMetricsOverride({
width: 100,
height: 200,
deviceScaleFactor: 2.5,
mobile: true,
scale: 1.2,
screenWidth: 100,
screenHeight: 200,
positionX: 0,
positionY: 0,
displayFeature: { orientation: 'vertical', offset: -30, maskLength: 20}
});
testRunner.log(response);
// invalid display feature orientation type string
response = await dp.Emulation.setDeviceMetricsOverride({
width: 100,
height: 200,
deviceScaleFactor: 2.5,
mobile: true,
scale: 1.2,
screenWidth: 100,
screenHeight: 200,
positionX: 0,
positionY: 0,
displayFeature: { orientation: 'vertical1', offset: -30, maskLength: 20}
});
testRunner.log(response);
// vertical: mask exceeds boundary
response = await dp.Emulation.setDeviceMetricsOverride({
width: 100,
height: 200,
deviceScaleFactor: 2.5,
mobile: true,
scale: 1.2,
screenWidth: 100,
screenHeight: 200,
positionX: 0,
positionY: 0,
displayFeature: { orientation: 'vertical', offset: 30, maskLength: 120}
});
testRunner.log(response);
// horizontal: ok
response = await dp.Emulation.setDeviceMetricsOverride({
width: 100,
height: 200,
deviceScaleFactor: 2.5,
mobile: true,
scale: 1.2,
screenWidth: 100,
screenHeight: 200,
positionX: 0,
positionY: 0,
displayFeature: { orientation: 'horizontal', offset: 30, maskLength: 120}
});
testRunner.log(response);
// horizontal: mask exceeds boundary
response = await dp.Emulation.setDeviceMetricsOverride({
width: 100,
height: 200,
deviceScaleFactor: 2.5,
mobile: true,
scale: 1.2,
screenWidth: 100,
screenHeight: 200,
positionX: 0,
positionY: 0,
displayFeature: { orientation: 'horizontal', offset: 130, maskLength: 120}
});
testRunner.log(response);
testRunner.completeTest();
});
\ No newline at end of file
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