blob: 31625e4895141b4fcd794fd3562cb0727564a4d8 [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/frame/screen_metrics_emulator.h"
#include "base/numerics/safe_conversions.h"
#include "third_party/blink/public/common/widget/visual_properties.h"
#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
namespace blink {
ScreenMetricsEmulator::ScreenMetricsEmulator(
WebFrameWidgetImpl* frame_widget,
const display::ScreenInfos& screen_infos,
const gfx::Size& widget_size,
const gfx::Size& visible_viewport_size,
const gfx::Rect& view_screen_rect,
const gfx::Rect& window_screen_rect)
: frame_widget_(frame_widget),
original_screen_infos_(screen_infos),
original_widget_size_(widget_size),
original_visible_viewport_size_(visible_viewport_size),
original_view_screen_rect_(view_screen_rect),
original_window_screen_rect_(window_screen_rect) {}
const display::ScreenInfo& ScreenMetricsEmulator::GetOriginalScreenInfo()
const {
return original_screen_infos_.current();
}
void ScreenMetricsEmulator::Trace(Visitor* vistor) const {
vistor->Trace(frame_widget_);
}
void ScreenMetricsEmulator::DisableAndApply() {
frame_widget_->SetScreenMetricsEmulationParameters(false, emulation_params_);
frame_widget_->SetScreenRects(original_view_screen_rect_,
original_window_screen_rect_);
frame_widget_->SetViewportSegments(original_root_viewport_segments_);
frame_widget_->SetScreenInfoAndSize(original_screen_infos_,
original_widget_size_,
original_visible_viewport_size_);
// The posture service will restore the original device posture coming from
// the platform.
frame_widget_->DisableDevicePostureOverrideForEmulation();
}
void ScreenMetricsEmulator::ChangeEmulationParams(
const DeviceEmulationParams& params) {
emulation_params_ = params;
Apply();
}
gfx::Point ScreenMetricsEmulator::ViewRectOrigin() {
gfx::Point widget_pos = original_view_rect().origin();
if (emulation_params_.view_position)
widget_pos = emulation_params_.view_position.value();
else if (!emulating_desktop())
widget_pos = gfx::Point();
return widget_pos;
}
void ScreenMetricsEmulator::Apply() {
// The WidgetScreenRect gets derived from the widget size of the main frame
// widget, not from the original WidgetScreenRect.
gfx::Size widget_size = original_widget_size_;
// The WindowScreenRect gets derived from the original WindowScreenRect,
// though.
gfx::Size window_size = original_window_rect().size();
// If either the width or height are specified by the emulator, then we use
// that size, and assume that they have the scale pre-applied to them.
if (emulation_params_.view_size.width()) {
widget_size.set_width(emulation_params_.view_size.width());
} else {
widget_size.set_width(
base::ClampRound(widget_size.width() / emulation_params_.scale));
}
if (emulation_params_.view_size.height()) {
widget_size.set_height(emulation_params_.view_size.height());
} else {
widget_size.set_height(
base::ClampRound(widget_size.height() / emulation_params_.scale));
}
// For mobile emulation, the window size is changed to match the widget size,
// as there are no window decorations around the widget.
if (!emulating_desktop())
window_size = widget_size;
gfx::Point widget_pos = original_view_rect().origin();
gfx::Point window_pos = original_window_rect().origin();
if (emulation_params_.view_position) {
// The emulated widget position overrides the widget and window positions.
widget_pos = emulation_params_.view_position.value();
window_pos = widget_pos;
} else if (!emulating_desktop()) {
// For mobile emulation, the widget and window are moved to 0,0 if not
// explicitly specified.
widget_pos = gfx::Point();
window_pos = widget_pos;
}
const display::ScreenInfo& original_screen_info =
original_screen_infos_.current();
gfx::Rect screen_rect = original_screen_info.rect;
if (!emulation_params_.screen_size.IsEmpty()) {
// The emulated screen size overrides the real one, and moves the screen's
// origin to 0,0.
screen_rect = gfx::Rect(gfx::Size(emulation_params_.screen_size));
} else if (!emulating_desktop()) {
// For mobile emulation, the screen is adjusted to match the position and
// size of the widget rect, if not explicitly specified.
screen_rect = gfx::Rect(widget_pos, widget_size);
}
float device_scale_factor = original_screen_info.device_scale_factor;
if (emulation_params_.device_scale_factor)
device_scale_factor = emulation_params_.device_scale_factor;
display::mojom::blink::ScreenOrientation orientation_type =
original_screen_info.orientation_type;
uint16_t orientation_angle = original_screen_info.orientation_angle;
if (emulation_params_.screen_orientation_type !=
display::mojom::blink::ScreenOrientation::kUndefined) {
orientation_type = emulation_params_.screen_orientation_type;
orientation_angle = emulation_params_.screen_orientation_angle;
}
// Pass three emulation parameters to the blink side:
// - we keep the real device scale factor in compositor to produce sharp image
// even when emulating different scale factor;
DeviceEmulationParams modified_emulation_params = emulation_params_;
modified_emulation_params.device_scale_factor =
original_screen_info.device_scale_factor;
frame_widget_->SetScreenMetricsEmulationParameters(
true, std::move(modified_emulation_params));
frame_widget_->SetScreenRects(gfx::Rect(widget_pos, widget_size),
gfx::Rect(window_pos, window_size));
// If there are no emulated viewport segments, use the emulated widget size
// instead. When we switch from emulated segments to not having any, we should
// have a single segment that matches the widget size.
bool has_emulated_segments = emulation_params_.viewport_segments.size();
if (has_emulated_segments) {
frame_widget_->SetViewportSegments(emulation_params_.viewport_segments);
} else {
std::vector<gfx::Rect> emulated_segments{
{0, 0, widget_size.width(), widget_size.height()}};
frame_widget_->SetViewportSegments(emulated_segments);
}
frame_widget_->OverrideDevicePostureForEmulation(
emulation_params_.device_posture);
display::ScreenInfos emulated_screen_infos = original_screen_infos_;
display::ScreenInfo& emulated_screen_info =
emulated_screen_infos.mutable_current();
emulated_screen_info.device_scale_factor = device_scale_factor;
emulated_screen_info.rect = screen_rect;
emulated_screen_info.available_rect = screen_rect;
emulated_screen_info.orientation_type = orientation_type;
emulated_screen_info.orientation_angle = orientation_angle;
frame_widget_->SetScreenInfoAndSize(emulated_screen_infos,
/*widget_size=*/widget_size,
/*visible_viewport_size=*/widget_size);
}
void ScreenMetricsEmulator::UpdateVisualProperties(
const VisualProperties& visual_properties) {
// Device emulation isn't supported for widgets that have auto resize mode
// enabled.
DCHECK(!frame_widget_->AutoResizeMode());
original_screen_infos_ = visual_properties.screen_infos;
original_widget_size_ = visual_properties.new_size;
original_visible_viewport_size_ = visual_properties.visible_viewport_size;
original_root_viewport_segments_ =
visual_properties.root_widget_viewport_segments;
Apply();
// Appy the compositor viewport rect and surface id allocation. The screen
// info is kept the same as the current ScreenInfo state. The screen info
// already was updated in |Apply| via |SetScreenInfoAndSize|.
frame_widget_->UpdateSurfaceAndCompositorRect(
visual_properties.local_surface_id.value_or(viz::LocalSurfaceId()),
visual_properties.compositor_viewport_pixel_rect);
}
void ScreenMetricsEmulator::OnUpdateScreenRects(
const gfx::Rect& view_screen_rect,
const gfx::Rect& window_screen_rect) {
original_view_screen_rect_ = view_screen_rect;
original_window_screen_rect_ = window_screen_rect;
if (emulating_desktop()) {
Apply();
}
}
} // namespace blink