Chromium Code Reviews| Index: ash/touch/touch_transformer_controller.cc |
| diff --git a/ash/touch/touch_transformer_controller.cc b/ash/touch/touch_transformer_controller.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..db080edabe0b98cda30ee5023849a422363e6004 |
| --- /dev/null |
| +++ b/ash/touch/touch_transformer_controller.cc |
| @@ -0,0 +1,223 @@ |
| +// Copyright 2014 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/touch/touch_transformer_controller.h" |
| + |
| +#include "ash/display/display_controller.h" |
| +#include "ash/display/display_manager.h" |
| +#include "ash/host/ash_window_tree_host.h" |
| +#include "ash/root_window_controller.h" |
| +#include "ash/shell.h" |
| +#include "ui/aura/window_tree_host.h" |
| +#include "ui/display/chromeos/display_configurator.h" |
| +#include "ui/display/types/chromeos/display_snapshot.h" |
| +#include "ui/events/x/device_data_manager.h" |
| + |
| +namespace ash { |
| + |
| +namespace { |
| + |
| +DisplayManager* GetDisplayManager() { |
| + return Shell::GetInstance()->display_manager(); |
| +} |
| + |
| +} // namespace |
| + |
| +// This function computes the extended mode TouchTransformer for |
| +// |touch_display|. The TouchTransformer maps the touch event position |
| +// from framebuffer size to the display size. |
| +ui::TouchTransformer |
| +TouchTransformerController::GetExtendedModeTouchTransformer( |
| + const DisplayInfo& touch_display, const gfx::Size& fb_size) const { |
| + ui::TouchTransformer ctm; |
| + if (touch_display.touch_device_id() == 0 || |
| + fb_size.width() == 0.0 || |
| + fb_size.height() == 0.0) |
| + return ctm; |
| + float width = touch_display.bounds_in_native().width(); |
| + float height = touch_display.bounds_in_native().height(); |
| + ctm.x_scale = width / fb_size.width(); |
| + ctm.x_offset = 0; |
| + ctm.y_scale = height / fb_size.height(); |
| + ctm.y_offset = 0; |
| + return ctm; |
| +} |
| + |
| +bool TouchTransformerController::ShouldComputeMirrorModeTouchTransformer( |
| + const DisplayInfo& touch_display) const { |
| + if (force_compute_mirror_mode_touch_transformer_) |
| + return true; |
| + |
| + if (touch_display.touch_device_id() == 0) |
| + return false; |
| + |
| + const ui::DisplayConfigurator::DisplayState* state = NULL; |
| + const std::vector<ui::DisplayConfigurator::DisplayState>& cached_displays = |
| + Shell::GetInstance()->display_configurator()->cached_displays(); |
| + for (size_t i = 0; i < cached_displays.size(); i++) { |
| + if (cached_displays[i].touch_device_id == touch_display.touch_device_id()) { |
| + state = &cached_displays[i]; |
| + break; |
| + } |
| + } |
| + |
| + if (!state || state->mirror_mode == state->display->native_mode() || |
| + !state->display->is_aspect_preserving_scaling()) { |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +// This function computes the mirror mode TouchTransformer for |touch_display|. |
| +// When internal monitor is applied a resolution that does not have |
| +// the same aspect ratio as its native resolution, there would be |
| +// blank regions in the letterboxing/pillarboxing mode. |
| +// The TouchTransformer will make sure the touch events on the blank region |
| +// have negative coordinates and touch events within the chrome region |
| +// have the correct positive coordinates. |
| +ui::TouchTransformer TouchTransformerController::GetMirrorModeTouchTransformer( |
| + const DisplayInfo& touch_display) const { |
| + ui::TouchTransformer ctm; |
| + if (!ShouldComputeMirrorModeTouchTransformer(touch_display)) |
| + return ctm; |
| + |
| + float mirror_width = touch_display.bounds_in_native().width(); |
| + float mirror_height = touch_display.bounds_in_native().height(); |
| + float native_width = 0; |
| + float native_height = 0; |
| + |
| + std::vector<DisplayMode> modes = touch_display.display_modes(); |
| + for (size_t i = 0; i < modes.size(); i++) { |
| + if (modes[i].native) { |
| + native_width = modes[i].size.width(); |
| + native_height = modes[i].size.height(); |
| + break; |
| + } |
| + } |
| + |
| + if (native_height == 0.0 || mirror_height == 0.0 || |
| + native_width == 0.0 || mirror_width == 0.0) |
| + return ctm; |
| + |
| + float native_ar = static_cast<float>(native_width) / |
| + static_cast<float>(native_height); |
| + float mirror_ar = static_cast<float>(mirror_width) / |
| + static_cast<float>(mirror_height); |
| + |
| + if (mirror_ar > native_ar) { // Letterboxing |
| + ctm.y_scale = mirror_ar / native_ar; |
| + ctm.y_offset = (1.0 / mirror_ar - 1.0 / native_ar) * 0.5 * mirror_width; |
|
ynovikov
2014/05/02 00:43:20
Nit: I think the formula looks prettier (symmetric
Yufeng Shen (Slow to review)
2014/05/02 15:14:08
of course :)
|
| + return ctm; |
| + } |
| + |
| + if (native_ar > mirror_ar) { // Pillarboxing |
| + ctm.x_scale = native_ar / mirror_ar; |
| + ctm.x_offset = (mirror_ar - native_ar) * 0.5 * mirror_height; |
|
ynovikov
2014/05/02 00:43:20
And
ctm.x_offset = (1.0 - native_ar / mirror_ar) *
|
| + return ctm; |
| + } |
| + |
| + return ctm; // Same aspect ratio - return identity |
| +} |
| + |
| +TouchTransformerController::TouchTransformerController() : |
| + force_compute_mirror_mode_touch_transformer_ (false) { |
| + Shell::GetInstance()->display_controller()->AddObserver(this); |
| +} |
| + |
| +TouchTransformerController::~TouchTransformerController() { |
| + Shell::GetInstance()->display_controller()->RemoveObserver(this); |
| +} |
| + |
| +void TouchTransformerController::UpdateTouchTransformer() const { |
| + ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| + device_manager->ClearTouchTransformerRecord(); |
| + |
| + // Display IDs and DisplayInfo for mirror or extended mode. |
| + int64 display1_id = gfx::Display::kInvalidDisplayID; |
| + int64 display2_id = gfx::Display::kInvalidDisplayID; |
| + DisplayInfo display1; |
| + DisplayInfo display2; |
| + // Display ID and DisplayInfo for single display mode. |
| + int64 single_display_id = gfx::Display::kInvalidDisplayID; |
| + DisplayInfo single_display; |
| + |
| + DisplayController* display_controller = |
| + Shell::GetInstance()->display_controller(); |
| + ui::MultipleDisplayState display_state = |
| + Shell::GetInstance()->display_configurator()->display_state(); |
| + // TODO(miletus) : Handle DUAL_EXTENDED with software mirroring. |
| + if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR || |
| + display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) { |
| + DisplayIdPair id_pair = GetDisplayManager()->GetCurrentDisplayIdPair(); |
| + display1_id = id_pair.first; |
| + display2_id = id_pair.second; |
| + DCHECK(display1_id != gfx::Display::kInvalidDisplayID && |
| + display2_id != gfx::Display::kInvalidDisplayID); |
| + display1 = GetDisplayManager()->GetDisplayInfo(display1_id); |
| + display2 = GetDisplayManager()->GetDisplayInfo(display2_id); |
| + } else { |
| + single_display_id = GetDisplayManager()->first_display_id(); |
| + DCHECK(single_display_id != gfx::Display::kInvalidDisplayID); |
| + single_display = GetDisplayManager()->GetDisplayInfo(single_display_id); |
| + } |
| + |
| + if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) { |
| + // In mirror mode, both displays share the same root window so |
| + // both display ids are associated with the root window. |
| + aura::Window* root = display_controller->GetPrimaryRootWindow(); |
| + RootWindowController::ForWindow(root)->ash_host()->UpdateDisplayID( |
| + display1_id, display2_id); |
| + device_manager->UpdateTouchInfoForDisplay( |
| + display1_id, |
| + display1.touch_device_id(), |
| + GetMirrorModeTouchTransformer(display1)); |
| + device_manager->UpdateTouchInfoForDisplay( |
| + display2_id, |
| + display2.touch_device_id(), |
| + GetMirrorModeTouchTransformer(display2)); |
| + return; |
| + } |
| + |
| + if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) { |
| + // In extended mode, each display is associated with one root window. |
| + aura::Window* root1 = |
| + display_controller->GetRootWindowForDisplayId(display1_id); |
| + aura::Window* root2 = |
| + display_controller->GetRootWindowForDisplayId(display2_id); |
| + RootWindowController::ForWindow(root1)->ash_host()->UpdateDisplayID( |
| + display1_id, gfx::Display::kInvalidDisplayID); |
| + RootWindowController::ForWindow(root2)->ash_host()->UpdateDisplayID( |
| + display2_id, gfx::Display::kInvalidDisplayID); |
| + gfx::Size fb_size = |
| + Shell::GetInstance()->display_configurator()->framebuffer_size(); |
| + device_manager->UpdateTouchInfoForDisplay( |
| + display1_id, |
| + display1.touch_device_id(), |
| + GetExtendedModeTouchTransformer(display1, fb_size)); |
| + device_manager->UpdateTouchInfoForDisplay( |
| + display2_id, |
| + display2.touch_device_id(), |
| + GetExtendedModeTouchTransformer(display2, fb_size)); |
| + return; |
| + } |
| + |
| + // Single display mode. The root window has one associated display id. |
| + aura::Window* root = |
| + display_controller->GetRootWindowForDisplayId(single_display.id()); |
| + RootWindowController::ForWindow(root)->ash_host()->UpdateDisplayID( |
| + single_display.id(), gfx::Display::kInvalidDisplayID); |
| + device_manager->UpdateTouchInfoForDisplay(single_display_id, |
| + single_display.touch_device_id(), |
| + ui::TouchTransformer()); |
| +} |
| + |
| +void TouchTransformerController::OnDisplaysInitialized() { |
| + UpdateTouchTransformer(); |
| +} |
| + |
| +void TouchTransformerController::OnDisplayConfigurationChanged() { |
| + UpdateTouchTransformer(); |
| +} |
| + |
| +} // namespace ash |