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