1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/display/overscan_calibrator.h" 6 7 #include "ash/display/display_controller.h" 8 #include "ash/display/display_info.h" 9 #include "ash/display/display_manager.h" 10 #include "ash/shell.h" 11 #include "ash/shell_window_ids.h" 12 #include "base/callback.h" 13 #include "ui/aura/window.h" 14 #include "ui/compositor/layer.h" 15 #include "ui/gfx/canvas.h" 16 17 namespace chromeos { 18 namespace { 19 20 // The opacity for the grey out borders. 21 const float kBorderOpacity = 0.5; 22 23 // The opacity for the arrows of the overscan calibration. 24 const float kArrowOpacity = 0.8; 25 26 // The height in pixel for the arrows to show the overscan calibration. 27 const int kCalibrationArrowHeight = 50; 28 29 // The gap between the boundary and calibration arrows. 30 const int kArrowGapWidth = 20; 31 32 // Draw the arrow for the overscan calibration to |canvas|. 33 void DrawTriangle(int x_offset, 34 int y_offset, 35 double rotation_degree, 36 gfx::Canvas* canvas) { 37 // Draw triangular arrows. 38 SkPaint content_paint; 39 content_paint.setStyle(SkPaint::kFill_Style); 40 content_paint.setColor(SkColorSetA(SK_ColorBLACK, kuint8max * kArrowOpacity)); 41 SkPaint border_paint; 42 border_paint.setStyle(SkPaint::kStroke_Style); 43 border_paint.setColor(SkColorSetA(SK_ColorWHITE, kuint8max * kArrowOpacity)); 44 45 SkPath base_path; 46 base_path.moveTo(0, SkIntToScalar(-kCalibrationArrowHeight)); 47 base_path.lineTo(SkIntToScalar(-kCalibrationArrowHeight), 0); 48 base_path.lineTo(SkIntToScalar(kCalibrationArrowHeight), 0); 49 base_path.close(); 50 51 SkPath path; 52 gfx::Transform rotate_transform; 53 rotate_transform.Rotate(rotation_degree); 54 gfx::Transform move_transform; 55 move_transform.Translate(x_offset, y_offset); 56 rotate_transform.ConcatTransform(move_transform); 57 base_path.transform(rotate_transform.matrix(), &path); 58 59 canvas->DrawPath(path, content_paint); 60 canvas->DrawPath(path, border_paint); 61 } 62 63 } // namespace 64 65 OverscanCalibrator::OverscanCalibrator( 66 const gfx::Display& target_display, const gfx::Insets& initial_insets) 67 : display_(target_display), 68 insets_(initial_insets), 69 initial_insets_(initial_insets), 70 committed_(false) { 71 // Undo the overscan calibration temporarily so that the user can see 72 // dark boundary and current overscan region. 73 ash::Shell::GetInstance()->display_controller()->SetOverscanInsets( 74 display_.id(), gfx::Insets()); 75 76 ash::internal::DisplayInfo info = ash::Shell::GetInstance()-> 77 display_manager()->GetDisplayInfo(display_.id()); 78 79 aura::RootWindow* root = ash::Shell::GetInstance()->display_controller()-> 80 GetRootWindowForDisplayId(display_.id()); 81 ui::Layer* parent_layer = ash::Shell::GetContainer( 82 root, ash::internal::kShellWindowId_OverlayContainer)->layer(); 83 84 calibration_layer_.reset(new ui::Layer()); 85 calibration_layer_->SetOpacity(0.5f); 86 calibration_layer_->SetBounds(parent_layer->bounds()); 87 calibration_layer_->set_delegate(this); 88 parent_layer->Add(calibration_layer_.get()); 89 } 90 91 OverscanCalibrator::~OverscanCalibrator() { 92 // Overscan calibration has finished without commit, so the display has to 93 // be the original offset. 94 if (!committed_) { 95 ash::Shell::GetInstance()->display_controller()->SetOverscanInsets( 96 display_.id(), initial_insets_); 97 } 98 } 99 100 void OverscanCalibrator::Commit() { 101 ash::Shell::GetInstance()->display_controller()->SetOverscanInsets( 102 display_.id(), insets_); 103 committed_ = true; 104 } 105 106 void OverscanCalibrator::Reset() { 107 insets_ = initial_insets_; 108 calibration_layer_->SchedulePaint(calibration_layer_->bounds()); 109 } 110 111 void OverscanCalibrator::UpdateInsets(const gfx::Insets& insets) { 112 insets_.Set(std::max(insets.top(), 0), 113 std::max(insets.left(), 0), 114 std::max(insets.bottom(), 0), 115 std::max(insets.right(), 0)); 116 calibration_layer_->SchedulePaint(calibration_layer_->bounds()); 117 } 118 119 void OverscanCalibrator::OnPaintLayer(gfx::Canvas* canvas) { 120 static const SkColor kTransparent = SkColorSetARGB(0, 0, 0, 0); 121 gfx::Rect full_bounds = calibration_layer_->bounds(); 122 gfx::Rect inner_bounds = full_bounds; 123 inner_bounds.Inset(insets_); 124 canvas->FillRect(full_bounds, SK_ColorBLACK); 125 canvas->FillRect(inner_bounds, kTransparent, SkXfermode::kClear_Mode); 126 127 gfx::Point center = inner_bounds.CenterPoint(); 128 int vertical_offset = inner_bounds.height() / 2 - kArrowGapWidth; 129 int horizontal_offset = inner_bounds.width() / 2 - kArrowGapWidth; 130 131 DrawTriangle(center.x(), center.y() + vertical_offset, 0, canvas); 132 DrawTriangle(center.x(), center.y() - vertical_offset, 180, canvas); 133 DrawTriangle(center.x() - horizontal_offset, center.y(), 90, canvas); 134 DrawTriangle(center.x() + horizontal_offset, center.y(), -90, canvas); 135 } 136 137 void OverscanCalibrator::OnDeviceScaleFactorChanged( 138 float device_scale_factor) { 139 // TODO(mukai): Cancel the overscan calibration when the device 140 // configuration has changed. 141 } 142 143 base::Closure OverscanCalibrator::PrepareForLayerBoundsChange() { 144 return base::Closure(); 145 } 146 147 } // namespace chromeos 148