This source file includes following definitions.
- IsValidRotationValue
- DegreesToRotation
- PointIsOverRadiusVector
- GetLayoutForRectangles
- UpdateDisplayLayout
- ValidateParamsForDisplay
- GetTargetDisplay
- SetInfoImpl
- SetInfo
- UpdateDisplayUnitInfoForPlatform
#include "chrome/browser/extensions/api/system_display/display_info_provider.h"
#include "ash/display/display_controller.h"
#include "ash/display/display_manager.h"
#include "ash/shell.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/strings/string_number_conversions.h"
#include "ui/gfx/display.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
using ash::DisplayManager;
namespace extensions {
using api::system_display::Bounds;
using api::system_display::DisplayUnitInfo;
using api::system_display::DisplayProperties;
using api::system_display::Insets;
namespace {
const float kDpi96 = 96.0;
const int kMaxBoundsOrigin = 200 * 1000;
bool IsValidRotationValue(int rotation) {
return rotation == 0 || rotation == 90 || rotation == 180 || rotation == 270;
}
gfx::Display::Rotation DegreesToRotation(int degrees) {
DCHECK(IsValidRotationValue(degrees));
switch (degrees) {
case 0:
return gfx::Display::ROTATE_0;
case 90:
return gfx::Display::ROTATE_90;
case 180:
return gfx::Display::ROTATE_180;
case 270:
return gfx::Display::ROTATE_270;
default:
return gfx::Display::ROTATE_0;
}
}
bool PointIsOverRadiusVector(const gfx::Point& point,
const gfx::Point& vector) {
return static_cast<int64>(point.x()) * static_cast<int64>(vector.y()) >=
static_cast<int64>(point.y()) * static_cast<int64>(vector.x());
}
ash::DisplayLayout GetLayoutForRectangles(const gfx::Rect& reference,
const gfx::Rect& rectangle) {
gfx::Point center(2 * (rectangle.x() - reference.x()) + rectangle.width(),
2 * (rectangle.y() - reference.y()) + rectangle.height());
gfx::Point down_diag(2 * reference.width(), 2 * reference.height());
bool is_top_right = PointIsOverRadiusVector(center, down_diag);
center.Offset(0, -2 * reference.height());
gfx::Point up_diag(-2 * reference.width(), 2 * reference.height());
bool is_bottom_right = PointIsOverRadiusVector(center, up_diag);
ash::DisplayLayout::Position position;
if (is_top_right) {
position = is_bottom_right ? ash::DisplayLayout::RIGHT :
ash::DisplayLayout::TOP;
} else {
position =
is_bottom_right ? ash::DisplayLayout::BOTTOM : ash::DisplayLayout::LEFT;
}
if (is_top_right == is_bottom_right) {
if (rectangle.y() > reference.y() + reference.height()) {
position = ash::DisplayLayout::BOTTOM;
} else if (rectangle.y() + rectangle.height() < reference.y()) {
position = ash::DisplayLayout::TOP;
}
} else {
if (rectangle.x() > reference.x() + reference.width()) {
position = ash::DisplayLayout::RIGHT;
} else if (rectangle.x() + rectangle.width() < reference.x()) {
position = ash::DisplayLayout::LEFT;
}
}
if (position == ash::DisplayLayout::LEFT ||
position == ash::DisplayLayout::RIGHT) {
return ash::DisplayLayout::FromInts(position, rectangle.y());
} else {
return ash::DisplayLayout::FromInts(position, rectangle.x());
}
}
void UpdateDisplayLayout(const gfx::Rect& primary_display_bounds,
int primary_display_id,
const gfx::Rect& target_display_bounds,
int target_display_id) {
ash::DisplayLayout layout = GetLayoutForRectangles(primary_display_bounds,
target_display_bounds);
ash::Shell::GetInstance()->display_manager()->
SetLayoutForCurrentDisplays(layout);
}
bool ValidateParamsForDisplay(const DisplayProperties& info,
const gfx::Display& display,
DisplayManager* display_manager,
int64 primary_display_id,
std::string* error) {
bool is_primary = display.id() == primary_display_id ||
(info.is_primary && *info.is_primary);
if (info.mirroring_source_id && !info.mirroring_source_id->empty()) {
int64 mirroring_id;
if (!base::StringToInt64(*info.mirroring_source_id, &mirroring_id) ||
display_manager->GetDisplayForId(mirroring_id).id() ==
gfx::Display::kInvalidDisplayID) {
*error = "Display " + *info.mirroring_source_id + " not found.";
return false;
}
if (*info.mirroring_source_id == base::Int64ToString(display.id())) {
*error = "Not allowed to mirror self.";
return false;
}
}
if (info.mirroring_source_id && (info.is_primary || info.bounds_origin_x ||
info.bounds_origin_y || info.rotation || info.overscan)) {
*error = "No other parameter should be set alongside mirroringSourceId.";
return false;
}
if (info.bounds_origin_x || info.bounds_origin_y) {
if (is_primary) {
*error = "Bounds origin not allowed for the primary display.";
return false;
}
if (info.bounds_origin_x &&
(*info.bounds_origin_x > kMaxBoundsOrigin ||
*info.bounds_origin_x < -kMaxBoundsOrigin)) {
*error = "Bounds origin x out of bounds.";
return false;
}
if (info.bounds_origin_y &&
(*info.bounds_origin_y > kMaxBoundsOrigin ||
*info.bounds_origin_y < -kMaxBoundsOrigin)) {
*error = "Bounds origin y out of bounds.";
return false;
}
}
if (info.rotation && !IsValidRotationValue(*info.rotation)) {
*error = "Invalid rotation.";
return false;
}
if (info.overscan) {
if (display.IsInternal()) {
*error = "Overscan changes not allowed for the internal monitor.";
return false;
}
if (info.overscan->left < 0 || info.overscan->top < 0 ||
info.overscan->right < 0 || info.overscan->bottom < 0) {
*error = "Negative overscan not allowed.";
return false;
}
const gfx::Insets overscan =
display_manager->GetOverscanInsets(display.id());
int screen_width = display.bounds().width() + overscan.width();
int screen_height = display.bounds().height() + overscan.height();
if ((info.overscan->left + info.overscan->right) * 2 > screen_width) {
*error = "Horizontal overscan is more than half of the screen width.";
return false;
}
if ((info.overscan->top + info.overscan->bottom) * 2 > screen_height) {
*error = "Vertical overscan is more than half of the screen height.";
return false;
}
}
return true;
}
gfx::Display GetTargetDisplay(const std::string& display_id_str,
DisplayManager* manager) {
int64 display_id;
if (!base::StringToInt64(display_id_str, &display_id)) {
return gfx::Display();
}
return manager->GetDisplayForId(display_id);
}
bool SetInfoImpl(const std::string& display_id_str,
const DisplayProperties& info,
std::string* error) {
DisplayManager* display_manager =
ash::Shell::GetInstance()->display_manager();
DCHECK(display_manager);
ash::DisplayController* display_controller =
ash::Shell::GetInstance()->display_controller();
DCHECK(display_controller);
const gfx::Display target = GetTargetDisplay(display_id_str, display_manager);
if (target.id() == gfx::Display::kInvalidDisplayID) {
*error = "Display not found.";
return false;
}
int64 display_id = target.id();
const gfx::Display& primary =
gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
if (!ValidateParamsForDisplay(info, target, display_manager, primary.id(),
error)) {
return false;
}
if (info.is_primary && *info.is_primary && target.id() != primary.id())
display_controller->SetPrimaryDisplayId(display_id);
if (info.mirroring_source_id &&
info.mirroring_source_id->empty() == display_manager->IsMirrored()) {
display_controller->ToggleMirrorMode();
}
if (info.overscan) {
display_manager->SetOverscanInsets(
display_id,
gfx::Insets(info.overscan->top, info.overscan->left,
info.overscan->bottom, info.overscan->right));
}
if (info.rotation) {
display_manager->SetDisplayRotation(display_id,
DegreesToRotation(*info.rotation));
}
gfx::Point new_bounds_origin = target.bounds().origin();
if (info.bounds_origin_x)
new_bounds_origin.set_x(*info.bounds_origin_x);
if (info.bounds_origin_y)
new_bounds_origin.set_y(*info.bounds_origin_y);
if (new_bounds_origin != target.bounds().origin()) {
gfx::Rect target_bounds = target.bounds();
target_bounds.Offset(new_bounds_origin.x() - target.bounds().x(),
new_bounds_origin.y() - target.bounds().y());
UpdateDisplayLayout(primary.bounds(), primary.id(),
target_bounds, target.id());
}
return true;
}
}
bool DisplayInfoProvider::SetInfo(const std::string& display_id,
const DisplayProperties& info,
std::string* error) {
return SetInfoImpl(display_id, info, error);
}
void DisplayInfoProvider::UpdateDisplayUnitInfoForPlatform(
const gfx::Display& display,
extensions::api::system_display::DisplayUnitInfo* unit) {
ash::DisplayManager* display_manager =
ash::Shell::GetInstance()->display_manager();
unit->name = display_manager->GetDisplayNameForId(display.id());
if (display_manager->IsMirrored()) {
unit->mirroring_source_id =
base::Int64ToString(display_manager->mirrored_display_id());
}
const float dpi = display.device_scale_factor() * kDpi96;
unit->dpi_x = dpi;
unit->dpi_y = dpi;
const gfx::Insets overscan_insets =
display_manager->GetOverscanInsets(display.id());
unit->overscan.left = overscan_insets.left();
unit->overscan.top = overscan_insets.top();
unit->overscan.right = overscan_insets.right();
unit->overscan.bottom = overscan_insets.bottom();
}
}