1// Copyright 2014 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 "ash/touch/touch_transformer_controller.h" 6 7#include "ash/display/display_controller.h" 8#include "ash/display/display_manager.h" 9#include "ash/host/ash_window_tree_host.h" 10#include "ash/root_window_controller.h" 11#include "ash/shell.h" 12#include "ui/aura/window_tree_host.h" 13#include "ui/display/chromeos/display_configurator.h" 14#include "ui/display/types/chromeos/display_snapshot.h" 15#include "ui/events/x/device_data_manager.h" 16 17namespace ash { 18 19namespace { 20 21DisplayManager* GetDisplayManager() { 22 return Shell::GetInstance()->display_manager(); 23} 24 25} // namespace 26 27// This function computes the extended mode TouchTransformer for 28// |touch_display|. The TouchTransformer maps the touch event position 29// from framebuffer size to the display size. 30gfx::Transform 31TouchTransformerController::GetExtendedModeTouchTransformer( 32 const DisplayInfo& touch_display, const gfx::Size& fb_size) const { 33 gfx::Transform ctm; 34 if (touch_display.touch_device_id() == 0 || 35 fb_size.width() == 0.0 || 36 fb_size.height() == 0.0) 37 return ctm; 38 float width = touch_display.bounds_in_native().width(); 39 float height = touch_display.bounds_in_native().height(); 40 ctm.Scale(width / fb_size.width(), height / fb_size.height()); 41 return ctm; 42} 43 44bool TouchTransformerController::ShouldComputeMirrorModeTouchTransformer( 45 const DisplayInfo& touch_display) const { 46 if (force_compute_mirror_mode_touch_transformer_) 47 return true; 48 49 if (touch_display.touch_device_id() == 0) 50 return false; 51 52 const ui::DisplayConfigurator::DisplayState* state = NULL; 53 const std::vector<ui::DisplayConfigurator::DisplayState>& cached_displays = 54 Shell::GetInstance()->display_configurator()->cached_displays(); 55 for (size_t i = 0; i < cached_displays.size(); i++) { 56 if (cached_displays[i].touch_device_id == touch_display.touch_device_id()) { 57 state = &cached_displays[i]; 58 break; 59 } 60 } 61 62 if (!state || state->mirror_mode == state->display->native_mode() || 63 !state->display->is_aspect_preserving_scaling()) { 64 return false; 65 } 66 return true; 67} 68 69// This function computes the mirror mode TouchTransformer for |touch_display|. 70// When internal monitor is applied a resolution that does not have 71// the same aspect ratio as its native resolution, there would be 72// blank regions in the letterboxing/pillarboxing mode. 73// The TouchTransformer will make sure the touch events on the blank region 74// have negative coordinates and touch events within the chrome region 75// have the correct positive coordinates. 76gfx::Transform TouchTransformerController::GetMirrorModeTouchTransformer( 77 const DisplayInfo& touch_display) const { 78 gfx::Transform ctm; 79 if (!ShouldComputeMirrorModeTouchTransformer(touch_display)) 80 return ctm; 81 82 float mirror_width = touch_display.bounds_in_native().width(); 83 float mirror_height = touch_display.bounds_in_native().height(); 84 float native_width = 0; 85 float native_height = 0; 86 87 std::vector<DisplayMode> modes = touch_display.display_modes(); 88 for (size_t i = 0; i < modes.size(); i++) { 89 if (modes[i].native) { 90 native_width = modes[i].size.width(); 91 native_height = modes[i].size.height(); 92 break; 93 } 94 } 95 96 if (native_height == 0.0 || mirror_height == 0.0 || 97 native_width == 0.0 || mirror_width == 0.0) 98 return ctm; 99 100 float native_ar = static_cast<float>(native_width) / 101 static_cast<float>(native_height); 102 float mirror_ar = static_cast<float>(mirror_width) / 103 static_cast<float>(mirror_height); 104 105 if (mirror_ar > native_ar) { // Letterboxing 106 // Translate before scale. 107 ctm.Translate(0.0, (1.0 - mirror_ar / native_ar) * 0.5 * mirror_height); 108 ctm.Scale(1.0, mirror_ar / native_ar); 109 return ctm; 110 } 111 112 if (native_ar > mirror_ar) { // Pillarboxing 113 // Translate before scale. 114 ctm.Translate((1.0 - native_ar / mirror_ar) * 0.5 * mirror_width, 0.0); 115 ctm.Scale(native_ar / mirror_ar, 1.0); 116 return ctm; 117 } 118 119 return ctm; // Same aspect ratio - return identity 120} 121 122TouchTransformerController::TouchTransformerController() : 123 force_compute_mirror_mode_touch_transformer_ (false) { 124 Shell::GetInstance()->display_controller()->AddObserver(this); 125} 126 127TouchTransformerController::~TouchTransformerController() { 128 Shell::GetInstance()->display_controller()->RemoveObserver(this); 129} 130 131void TouchTransformerController::UpdateTouchTransformer() const { 132 ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); 133 device_manager->ClearTouchTransformerRecord(); 134 135 // Display IDs and DisplayInfo for mirror or extended mode. 136 int64 display1_id = gfx::Display::kInvalidDisplayID; 137 int64 display2_id = gfx::Display::kInvalidDisplayID; 138 DisplayInfo display1; 139 DisplayInfo display2; 140 // Display ID and DisplayInfo for single display mode. 141 int64 single_display_id = gfx::Display::kInvalidDisplayID; 142 DisplayInfo single_display; 143 144 DisplayController* display_controller = 145 Shell::GetInstance()->display_controller(); 146 ui::MultipleDisplayState display_state = 147 Shell::GetInstance()->display_configurator()->display_state(); 148 if (display_state == ui::MULTIPLE_DISPLAY_STATE_INVALID || 149 display_state == ui::MULTIPLE_DISPLAY_STATE_HEADLESS) { 150 return; 151 } else if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR || 152 display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) { 153 // TODO(miletus) : Handle DUAL_EXTENDED with software mirroring. 154 DisplayIdPair id_pair = GetDisplayManager()->GetCurrentDisplayIdPair(); 155 display1_id = id_pair.first; 156 display2_id = id_pair.second; 157 DCHECK(display1_id != gfx::Display::kInvalidDisplayID && 158 display2_id != gfx::Display::kInvalidDisplayID); 159 display1 = GetDisplayManager()->GetDisplayInfo(display1_id); 160 display2 = GetDisplayManager()->GetDisplayInfo(display2_id); 161 } else { 162 single_display_id = GetDisplayManager()->first_display_id(); 163 DCHECK(single_display_id != gfx::Display::kInvalidDisplayID); 164 single_display = GetDisplayManager()->GetDisplayInfo(single_display_id); 165 } 166 167 if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) { 168 // In mirror mode, both displays share the same root window so 169 // both display ids are associated with the root window. 170 aura::Window* root = display_controller->GetPrimaryRootWindow(); 171 RootWindowController::ForWindow(root)->ash_host()->UpdateDisplayID( 172 display1_id, display2_id); 173 device_manager->UpdateTouchInfoForDisplay( 174 display1_id, 175 display1.touch_device_id(), 176 GetMirrorModeTouchTransformer(display1)); 177 device_manager->UpdateTouchInfoForDisplay( 178 display2_id, 179 display2.touch_device_id(), 180 GetMirrorModeTouchTransformer(display2)); 181 return; 182 } 183 184 if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) { 185 // TODO(miletus) : Handle the case the state is DUAL_EXTENDED but it 186 // is actually doing software mirroring. 187 if (GetDisplayManager()->software_mirroring_enabled()) 188 return; 189 // In extended mode, each display is associated with one root window. 190 aura::Window* root1 = 191 display_controller->GetRootWindowForDisplayId(display1_id); 192 aura::Window* root2 = 193 display_controller->GetRootWindowForDisplayId(display2_id); 194 RootWindowController::ForWindow(root1)->ash_host()->UpdateDisplayID( 195 display1_id, gfx::Display::kInvalidDisplayID); 196 RootWindowController::ForWindow(root2)->ash_host()->UpdateDisplayID( 197 display2_id, gfx::Display::kInvalidDisplayID); 198 gfx::Size fb_size = 199 Shell::GetInstance()->display_configurator()->framebuffer_size(); 200 device_manager->UpdateTouchInfoForDisplay( 201 display1_id, 202 display1.touch_device_id(), 203 GetExtendedModeTouchTransformer(display1, fb_size)); 204 device_manager->UpdateTouchInfoForDisplay( 205 display2_id, 206 display2.touch_device_id(), 207 GetExtendedModeTouchTransformer(display2, fb_size)); 208 return; 209 } 210 211 // Single display mode. The root window has one associated display id. 212 aura::Window* root = 213 display_controller->GetRootWindowForDisplayId(single_display.id()); 214 RootWindowController::ForWindow(root)->ash_host()->UpdateDisplayID( 215 single_display.id(), gfx::Display::kInvalidDisplayID); 216 device_manager->UpdateTouchInfoForDisplay(single_display_id, 217 single_display.touch_device_id(), 218 gfx::Transform()); 219} 220 221void TouchTransformerController::OnDisplaysInitialized() { 222 UpdateTouchTransformer(); 223} 224 225void TouchTransformerController::OnDisplayConfigurationChanged() { 226 UpdateTouchTransformer(); 227} 228 229} // namespace ash 230