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 "ui/display/chromeos/touchscreen_delegate_impl.h"
6
7#include <cmath>
8#include <set>
9
10#include "ui/display/types/chromeos/display_mode.h"
11#include "ui/display/types/chromeos/display_snapshot.h"
12#include "ui/display/types/chromeos/touchscreen_device_manager.h"
13
14namespace ui {
15
16TouchscreenDelegateImpl::TouchscreenDelegateImpl(
17    scoped_ptr<TouchscreenDeviceManager> touch_device_manager)
18    : touch_device_manager_(touch_device_manager.Pass()) {}
19
20TouchscreenDelegateImpl::~TouchscreenDelegateImpl() {}
21
22void TouchscreenDelegateImpl::AssociateTouchscreens(
23    std::vector<DisplayConfigurator::DisplayState>* displays) {
24  std::set<int> no_match_touchscreen;
25  std::vector<TouchscreenDevice> devices = touch_device_manager_->GetDevices();
26
27  int internal_touchscreen = -1;
28  for (size_t i = 0; i < devices.size(); ++i) {
29    if (devices[i].is_internal) {
30      internal_touchscreen = i;
31      break;
32    }
33  }
34
35  DisplayConfigurator::DisplayState* internal_state = NULL;
36  for (size_t i = 0; i < displays->size(); ++i) {
37    DisplayConfigurator::DisplayState* state = &(*displays)[i];
38    if (state->display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL &&
39        state->display->native_mode() &&
40        state->touch_device_id == 0) {
41      internal_state = state;
42      break;
43    }
44  }
45
46  if (internal_state && internal_touchscreen >= 0) {
47    internal_state->touch_device_id = devices[internal_touchscreen].id;
48    VLOG(2) << "Found internal touchscreen for internal display "
49            << internal_state->display->display_id() << " touch_device_id "
50            << internal_state->touch_device_id << " size "
51            << devices[internal_touchscreen].size.ToString();
52  }
53
54  for (size_t i = 0; i < devices.size(); ++i) {
55    if (internal_state &&
56        internal_state->touch_device_id == devices[i].id)
57      continue;
58    bool found_mapping = false;
59    for (size_t j = 0; j < displays->size(); ++j) {
60      DisplayConfigurator::DisplayState* state = &(*displays)[j];
61      const DisplayMode* mode = state->display->native_mode();
62      if (state->touch_device_id != 0 || !mode)
63        continue;
64
65      // Allow 1 pixel difference between screen and touchscreen
66      // resolutions. Because in some cases for monitor resolution
67      // 1024x768 touchscreen's resolution would be 1024x768, but for
68      // some 1023x767. It really depends on touchscreen's firmware
69      // configuration.
70      if (std::abs(mode->size().width() - devices[i].size.width()) <= 1 &&
71          std::abs(mode->size().height() - devices[i].size.height()) <= 1) {
72        state->touch_device_id = devices[i].id;
73
74        VLOG(2) << "Found touchscreen for display "
75                << state->display->display_id() << " touch_device_id "
76                << state->touch_device_id << " size "
77                << devices[i].size.ToString();
78        found_mapping = true;
79        break;
80      }
81    }
82
83    if (!found_mapping) {
84      no_match_touchscreen.insert(devices[i].id);
85      VLOG(2) << "No matching display for touch_device_id "
86              << devices[i].id << " size " << devices[i].size.ToString();
87    }
88  }
89
90  // Sometimes we can't find a matching screen for the touchscreen, e.g.
91  // due to the touchscreen's reporting range having no correlation with the
92  // screen's resolution. In this case, we arbitrarily assign unmatched
93  // touchscreens to unmatched screens.
94  for (std::set<int>::iterator it = no_match_touchscreen.begin();
95       it != no_match_touchscreen.end();
96       ++it) {
97    for (size_t i = 0; i < displays->size(); ++i) {
98      DisplayConfigurator::DisplayState* state = &(*displays)[i];
99      if (state->display->type() != DISPLAY_CONNECTION_TYPE_INTERNAL &&
100          state->display->native_mode() != NULL &&
101          state->touch_device_id == 0) {
102        state->touch_device_id = *it;
103        VLOG(2) << "Arbitrarily matching touchscreen "
104                << state->touch_device_id << " to display "
105                << state->display->display_id();
106        break;
107      }
108    }
109  }
110}
111
112}  // namespace ui
113