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::internal::DisplayInfo info = ash::Shell::GetInstance()-> 74 display_manager()->GetDisplayInfo(display_.id()); 75 76 aura::Window* root = ash::Shell::GetInstance()->display_controller()-> 77 GetRootWindowForDisplayId(display_.id()); 78 ui::Layer* parent_layer = ash::Shell::GetContainer( 79 root, ash::internal::kShellWindowId_OverlayContainer)->layer(); 80 81 calibration_layer_.reset(new ui::Layer()); 82 calibration_layer_->SetOpacity(0.5f); 83 calibration_layer_->SetBounds(parent_layer->bounds()); 84 calibration_layer_->set_delegate(this); 85 parent_layer->Add(calibration_layer_.get()); 86 } 87 88 OverscanCalibrator::~OverscanCalibrator() { 89 // Overscan calibration has finished without commit, so the display has to 90 // be the original offset. 91 if (!committed_) { 92 ash::Shell::GetInstance()->display_controller()->SetOverscanInsets( 93 display_.id(), initial_insets_); 94 } 95 } 96 97 void OverscanCalibrator::Commit() { 98 ash::Shell::GetInstance()->display_controller()->SetOverscanInsets( 99 display_.id(), insets_); 100 committed_ = true; 101 } 102 103 void OverscanCalibrator::Reset() { 104 insets_ = initial_insets_; 105 calibration_layer_->SchedulePaint(calibration_layer_->bounds()); 106 } 107 108 void OverscanCalibrator::UpdateInsets(const gfx::Insets& insets) { 109 insets_.Set(std::max(insets.top(), 0), 110 std::max(insets.left(), 0), 111 std::max(insets.bottom(), 0), 112 std::max(insets.right(), 0)); 113 calibration_layer_->SchedulePaint(calibration_layer_->bounds()); 114 } 115 116 void OverscanCalibrator::OnPaintLayer(gfx::Canvas* canvas) { 117 static const SkColor kTransparent = SkColorSetARGB(0, 0, 0, 0); 118 gfx::Rect full_bounds = calibration_layer_->bounds(); 119 gfx::Rect inner_bounds = full_bounds; 120 inner_bounds.Inset(insets_); 121 canvas->FillRect(full_bounds, SK_ColorBLACK); 122 canvas->FillRect(inner_bounds, kTransparent, SkXfermode::kClear_Mode); 123 124 gfx::Point center = inner_bounds.CenterPoint(); 125 int vertical_offset = inner_bounds.height() / 2 - kArrowGapWidth; 126 int horizontal_offset = inner_bounds.width() / 2 - kArrowGapWidth; 127 128 DrawTriangle(center.x(), center.y() + vertical_offset, 0, canvas); 129 DrawTriangle(center.x(), center.y() - vertical_offset, 180, canvas); 130 DrawTriangle(center.x() - horizontal_offset, center.y(), 90, canvas); 131 DrawTriangle(center.x() + horizontal_offset, center.y(), -90, canvas); 132 } 133 134 void OverscanCalibrator::OnDeviceScaleFactorChanged( 135 float device_scale_factor) { 136 // TODO(mukai): Cancel the overscan calibration when the device 137 // configuration has changed. 138 } 139 140 base::Closure OverscanCalibrator::PrepareForLayerBoundsChange() { 141 return base::Closure(); 142 } 143 144 } // namespace chromeos 145