| // Copyright (c) 2012 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 "ash/display/overscan_calibrator.h" |
| |
| #include <stdint.h> |
| |
| #include <limits> |
| |
| #include "ash/display/window_tree_host_manager.h" |
| #include "ash/public/cpp/shell_window_ids.h" |
| #include "ash/shell.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "third_party/skia/include/core/SkPaint.h" |
| #include "third_party/skia/include/core/SkPath.h" |
| #include "ui/aura/window.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/compositor/paint_recorder.h" |
| #include "ui/display/manager/display_manager.h" |
| #include "ui/display/manager/managed_display_info.h" |
| #include "ui/gfx/canvas.h" |
| |
| namespace ash { |
| namespace { |
| |
| // The opacity for the arrows of the overscan calibration. |
| const float kArrowOpacity = 0.8; |
| |
| // The height in pixel for the arrows to show the overscan calibration. |
| const int kCalibrationArrowHeight = 70; |
| |
| // The gap between the boundary and calibration arrows. |
| const int kArrowGapWidth = 0; |
| |
| // Draw the arrow for the overscan calibration to |canvas|. |
| void DrawTriangle(int x_offset, |
| int y_offset, |
| double rotation_degree, |
| gfx::Canvas* canvas) { |
| // Draw triangular arrows. |
| cc::PaintFlags content_flags; |
| content_flags.setStyle(cc::PaintFlags::kFill_Style); |
| content_flags.setColor(SkColorSetA( |
| SK_ColorBLACK, std::numeric_limits<uint8_t>::max() * kArrowOpacity)); |
| cc::PaintFlags border_flags; |
| border_flags.setStyle(cc::PaintFlags::kStroke_Style); |
| border_flags.setColor(SkColorSetA( |
| SK_ColorWHITE, std::numeric_limits<uint8_t>::max() * kArrowOpacity)); |
| |
| SkPath base_path; |
| base_path.moveTo(0, 0); |
| base_path.lineTo(SkIntToScalar(-kCalibrationArrowHeight), |
| SkIntToScalar(-kCalibrationArrowHeight)); |
| base_path.lineTo(SkIntToScalar(kCalibrationArrowHeight), |
| SkIntToScalar(-kCalibrationArrowHeight)); |
| base_path.close(); |
| |
| SkPath path; |
| gfx::Transform rotate_transform; |
| rotate_transform.Rotate(rotation_degree); |
| gfx::Transform move_transform; |
| move_transform.Translate(x_offset, y_offset); |
| rotate_transform.ConcatTransform(move_transform); |
| base_path.transform(rotate_transform.matrix(), &path); |
| |
| canvas->DrawPath(path, content_flags); |
| canvas->DrawPath(path, border_flags); |
| } |
| |
| } // namespace |
| |
| OverscanCalibrator::OverscanCalibrator(const display::Display& target_display, |
| const gfx::Insets& initial_insets) |
| : display_(target_display), |
| insets_(initial_insets), |
| initial_insets_(initial_insets), |
| committed_(false) { |
| // Undo the overscan calibration temporarily so that the user can see |
| // dark boundary and current overscan region. |
| ash::Shell::Get()->window_tree_host_manager()->SetOverscanInsets( |
| display_.id(), gfx::Insets()); |
| |
| display::ManagedDisplayInfo info = |
| ash::Shell::Get()->display_manager()->GetDisplayInfo(display_.id()); |
| |
| aura::Window* root = ash::Shell::GetRootWindowForDisplayId(display_.id()); |
| ui::Layer* parent_layer = |
| ash::Shell::GetContainer(root, ash::kShellWindowId_OverlayContainer) |
| ->layer(); |
| |
| calibration_layer_.reset(new ui::Layer()); |
| calibration_layer_->SetOpacity(0.5f); |
| calibration_layer_->SetBounds(parent_layer->bounds()); |
| calibration_layer_->set_delegate(this); |
| parent_layer->Add(calibration_layer_.get()); |
| } |
| |
| OverscanCalibrator::~OverscanCalibrator() { |
| // Overscan calibration has finished without commit, so the display has to |
| // be the original offset. |
| if (!committed_) { |
| ash::Shell::Get()->window_tree_host_manager()->SetOverscanInsets( |
| display_.id(), initial_insets_); |
| } |
| } |
| |
| void OverscanCalibrator::Commit() { |
| ash::Shell::Get()->window_tree_host_manager()->SetOverscanInsets( |
| display_.id(), insets_); |
| committed_ = true; |
| } |
| |
| void OverscanCalibrator::Reset() { |
| insets_ = initial_insets_; |
| calibration_layer_->SchedulePaint(calibration_layer_->bounds()); |
| } |
| |
| void OverscanCalibrator::UpdateInsets(const gfx::Insets& insets) { |
| insets_.Set(std::max(insets.top(), 0), std::max(insets.left(), 0), |
| std::max(insets.bottom(), 0), std::max(insets.right(), 0)); |
| calibration_layer_->SchedulePaint(calibration_layer_->bounds()); |
| } |
| |
| void OverscanCalibrator::OnPaintLayer(const ui::PaintContext& context) { |
| ui::PaintRecorder recorder(context, calibration_layer_->size()); |
| static const SkColor kTransparent = SkColorSetARGB(0, 0, 0, 0); |
| gfx::Rect full_bounds = calibration_layer_->bounds(); |
| gfx::Rect inner_bounds = full_bounds; |
| inner_bounds.Inset(insets_); |
| recorder.canvas()->FillRect(full_bounds, SK_ColorBLACK); |
| recorder.canvas()->FillRect(inner_bounds, kTransparent, SkBlendMode::kClear); |
| |
| gfx::Point center = inner_bounds.CenterPoint(); |
| int vertical_offset = inner_bounds.height() / 2 - kArrowGapWidth; |
| int horizontal_offset = inner_bounds.width() / 2 - kArrowGapWidth; |
| |
| gfx::Canvas* canvas = recorder.canvas(); |
| DrawTriangle(center.x(), center.y() + vertical_offset, 0, canvas); |
| DrawTriangle(center.x(), center.y() - vertical_offset, 180, canvas); |
| DrawTriangle(center.x() - horizontal_offset, center.y(), 90, canvas); |
| DrawTriangle(center.x() + horizontal_offset, center.y(), -90, canvas); |
| } |
| |
| void OverscanCalibrator::OnDeviceScaleFactorChanged( |
| float old_device_scale_factor, |
| float new_device_scale_factor) { |
| // TODO(mukai): Cancel the overscan calibration when the device |
| // configuration has changed. |
| } |
| |
| } // namespace ash |