blob: 5368c0136ae698ee28ef00769d8f51870bbe15c6 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromecast/browser/cast_display_configurator.h"
#include <math.h>
#include <algorithm>
#include <string>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "chromecast/base/cast_features.h"
#include "chromecast/browser/cast_touch_device_manager.h"
#include "chromecast/graphics/cast_display_util.h"
#include "chromecast/graphics/cast_screen.h"
#include "chromecast/public/graphics_properties_shlib.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/native_display_delegate.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/ozone/public/ozone_platform.h"
namespace chromecast {
namespace shell {
namespace {
constexpr int64_t kStubDisplayId = 1;
constexpr char kCastGraphicsHeight[] = "cast-graphics-height";
constexpr char kCastGraphicsWidth[] = "cast-graphics-width";
constexpr char kDisplayRotation[] = "display-rotation";
// Helper to return the screen resolution (device pixels)
// to use.
gfx::Size GetScreenResolution() {
gfx::Size res(1280, 720);
const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (!chromecast::IsFeatureEnabled(kTripleBuffer720) &&
GraphicsPropertiesShlib::IsSupported(GraphicsPropertiesShlib::k1080p,
cmd_line->argv())) {
res = gfx::Size(1920, 1080);
}
int cast_gfx_width = 0;
int cast_gfx_height = 0;
if (base::StringToInt(cmd_line->GetSwitchValueASCII(kCastGraphicsWidth),
&cast_gfx_width) &&
base::StringToInt(cmd_line->GetSwitchValueASCII(kCastGraphicsHeight),
&cast_gfx_height) &&
cast_gfx_width > 0 && cast_gfx_height > 0) {
res.set_width(cast_gfx_width);
res.set_height(cast_gfx_height);
}
return res;
}
display::Display::Rotation GetRotationFromCommandLine() {
std::string rotation =
base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
kDisplayRotation);
if (rotation == "90")
return display::Display::ROTATE_90;
else if (rotation == "180")
return display::Display::ROTATE_180;
else if (rotation == "270")
return display::Display::ROTATE_270;
else
return display::Display::ROTATE_0;
}
gfx::Rect GetScreenBounds(const gfx::Size& size_in_pixels,
display::Display::Rotation rotation) {
switch (rotation) {
case display::Display::ROTATE_90:
case display::Display::ROTATE_270:
return gfx::Rect(
gfx::Size(size_in_pixels.height(), size_in_pixels.width()));
case display::Display::ROTATE_0:
case display::Display::ROTATE_180:
default:
return gfx::Rect(size_in_pixels);
}
}
} // namespace
CastDisplayConfigurator::CastDisplayConfigurator(CastScreen* screen)
: delegate_(
#if defined(USE_OZONE)
ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate()
#else
nullptr
#endif
),
touch_device_manager_(std::make_unique<CastTouchDeviceManager>()),
display_(nullptr),
cast_screen_(screen),
weak_factory_(this) {
if (delegate_) {
delegate_->AddObserver(this);
delegate_->Initialize();
ForceInitialConfigure();
} else {
ConfigureDisplayFromCommandLine();
}
}
CastDisplayConfigurator::~CastDisplayConfigurator() {
if (delegate_)
delegate_->RemoveObserver(this);
}
// display::NativeDisplayObserver interface
void CastDisplayConfigurator::OnConfigurationChanged() {
DCHECK(delegate_);
delegate_->GetDisplays(base::Bind(
&CastDisplayConfigurator::OnDisplaysAcquired, weak_factory_.GetWeakPtr(),
false /* force_initial_configure */));
}
void CastDisplayConfigurator::ConfigureDisplayFromCommandLine() {
const gfx::Size size = GetScreenResolution();
UpdateScreen(kStubDisplayId, gfx::Rect(size), GetDeviceScaleFactor(size),
GetRotationFromCommandLine());
}
void CastDisplayConfigurator::SetColorMatrix(
const std::vector<float>& color_matrix) {
if (!delegate_ || !display_)
return;
delegate_->SetColorMatrix(display_->display_id(), color_matrix);
}
void CastDisplayConfigurator::SetGammaCorrection(
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
const std::vector<display::GammaRampRGBEntry>& gamma_lut) {
if (!delegate_ || !display_)
return;
delegate_->SetGammaCorrection(display_->display_id(), degamma_lut, gamma_lut);
}
void CastDisplayConfigurator::ForceInitialConfigure() {
if (!delegate_)
return;
delegate_->GetDisplays(base::Bind(
&CastDisplayConfigurator::OnDisplaysAcquired, weak_factory_.GetWeakPtr(),
true /* force_initial_configure */));
}
void CastDisplayConfigurator::OnDisplaysAcquired(
bool force_initial_configure,
const std::vector<display::DisplaySnapshot*>& displays) {
DCHECK(delegate_);
if (displays.empty()) {
LOG(WARNING) << "No displays detected, skipping display init.";
return;
}
if (displays.size() > 1) {
LOG(WARNING) << "Multiple display detected, using the first one.";
}
display_ = displays[0];
if (!display_->native_mode()) {
LOG(WARNING) << "Display " << display_->display_id()
<< " doesn't have a native mode.";
return;
}
gfx::Point origin;
gfx::Size native_size(display_->native_mode()->size());
if (force_initial_configure) {
// For initial configuration, pass the native geometry to gfx::Screen
// before calling Configure(), so that this information is available
// to chrome during startup. Otherwise we will not have a valid display
// during the first queries to display::Screen.
UpdateScreen(display_->display_id(), gfx::Rect(origin, native_size),
GetDeviceScaleFactor(native_size),
GetRotationFromCommandLine());
}
delegate_->Configure(
*display_, display_->native_mode(), origin,
base::BindRepeating(&CastDisplayConfigurator::OnDisplayConfigured,
weak_factory_.GetWeakPtr(), display_,
display_->native_mode(), origin));
}
void CastDisplayConfigurator::OnDisplayConfigured(
display::DisplaySnapshot* display,
const display::DisplayMode* mode,
const gfx::Point& origin,
bool success) {
DCHECK(display);
DCHECK(mode);
DCHECK_EQ(display, display_);
const gfx::Rect bounds(origin, mode->size());
VLOG(1) << __func__ << " success=" << success
<< " bounds=" << bounds.ToString();
if (success) {
// Need to update the display state otherwise it becomes stale.
display_->set_current_mode(mode);
display_->set_origin(origin);
UpdateScreen(display_->display_id(), bounds,
GetDeviceScaleFactor(display->native_mode()->size()),
GetRotationFromCommandLine());
} else {
LOG(FATAL) << "Failed to configure display";
}
}
void CastDisplayConfigurator::UpdateScreen(
int64_t display_id,
const gfx::Rect& bounds,
float device_scale_factor,
display::Display::Rotation rotation) {
cast_screen_->OnDisplayChanged(display_id, device_scale_factor, rotation,
GetScreenBounds(bounds.size(), rotation));
touch_device_manager_->OnDisplayConfigured(display_id, rotation, bounds);
}
} // namespace shell
} // namespace chromecast