summaryrefslogtreecommitdiffstats
path: root/chromeos/display
diff options
context:
space:
mode:
authormiletus@chromium.org <miletus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-13 19:18:38 +0000
committermiletus@chromium.org <miletus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-13 19:18:38 +0000
commit06b20fe95e55c66ac56d1ea09a5fcc32cf4c7373 (patch)
tree582fd3115e4d5c99bfbd5e2a6acfda468efa20d6 /chromeos/display
parent4db9800ef1f1c4062c6a00fcd175e38988c30087 (diff)
downloadchromium_src-06b20fe95e55c66ac56d1ea09a5fcc32cf4c7373.zip
chromium_src-06b20fe95e55c66ac56d1ea09a5fcc32cf4c7373.tar.gz
chromium_src-06b20fe95e55c66ac56d1ea09a5fcc32cf4c7373.tar.bz2
Correct X event CTM calculation for multi-monitor case
When there are multi-monitors, X will scale the touch event's coordinate from device coordinate to screen coordinate. We then in Chrome compute a CTM that will scale/translate the X events to the correct RootWindow's bounds. The scaling in X are done in floating points but when finally converted to ui::TouchEvent's location as integers, there could be +-1 happening which could make the touch events appear as out of bound of any RootWindow and thus get lost. One symptom is that when move fingers to the upper edge of external monitor and lift, the touch release event could be lost and the finger seems get stuck on the screen. We have a small fix in calculating CTM X/Y scale/offset by using framebuffer_width/height - 1 instead of framebuffer_width/height. Also when converting X event's coordinate to ui::TouchEvent's location, use rounding instead of static_cast<int>(double), which seems more correct. BUG=315942 TEST=Connect Pixel to external touch monitor, turn on HUD projection by Ctrl + Shift + 9. Move fingers on external monitor to edges and lift. Make sure no fingers get stuck at the edges. Review URL: https://codereview.chromium.org/69653002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@234871 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos/display')
-rw-r--r--chromeos/display/output_configurator.cc51
-rw-r--r--chromeos/display/output_configurator.h9
-rw-r--r--chromeos/display/output_configurator_unittest.cc40
3 files changed, 90 insertions, 10 deletions
diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc
index 1a3cc31..67da273 100644
--- a/chromeos/display/output_configurator.cc
+++ b/chromeos/display/output_configurator.cc
@@ -932,16 +932,8 @@ bool OutputConfigurator::EnterState(
for (size_t i = 0; i < updated_outputs.size(); ++i) {
OutputSnapshot* output = &updated_outputs[i];
- if (output->touch_device_id) {
- const ModeInfo* mode_info =
- GetModeInfo(*output, output->selected_mode);
- DCHECK(mode_info);
- CoordinateTransformation* ctm = &(output->transform);
- ctm->x_scale = static_cast<float>(mode_info->width) / width;
- ctm->x_offset = static_cast<float>(output->x) / width;
- ctm->y_scale = static_cast<float>(mode_info->height) / height;
- ctm->y_offset = static_cast<float>(output->y) / height;
- }
+ if (output->touch_device_id)
+ output->transform = GetExtendedModeCTM(*output, width, height);
}
break;
}
@@ -1040,6 +1032,45 @@ OutputConfigurator::GetMirrorModeCTM(
return ctm; // Same aspect ratio - return identity
}
+OutputConfigurator::CoordinateTransformation
+OutputConfigurator::GetExtendedModeCTM(
+ const OutputConfigurator::OutputSnapshot& output,
+ int framebuffer_width,
+ int framebuffer_height) {
+ CoordinateTransformation ctm; // Default to identity
+ const ModeInfo* mode_info = GetModeInfo(output, output.selected_mode);
+ DCHECK(mode_info);
+ if (!mode_info)
+ return ctm;
+ // An example of how to calculate the CTM.
+ // Suppose we have 2 monitors, the first one has size 1366 x 768.
+ // The second one has size 2560 x 1600
+ // The total size of framebuffer is 2560 x 2428
+ // where 2428 = 768 + 60 (hidden gap) + 1600
+ // and the sceond monitor is translated to Point (0, 828) in the
+ // framebuffer.
+ // X will first map input event location to [0, 2560) x [0, 2428),
+ // then apply CTM on it.
+ // So to compute CTM, for monitor1, we have
+ // x_scale = (1366 - 1) / (2560 - 1)
+ // x_offset = 0 / (2560 - 1)
+ // y_scale = (768 - 1) / (2428 - 1)
+ // y_offset = 0 / (2428 -1)
+ // For Monitor 2, we have
+ // x_scale = (2560 - 1) / (2560 - 1)
+ // x_offset = 0 / (2560 - 1)
+ // y_scale = (1600 - 1) / (2428 - 1)
+ // y_offset = 828 / (2428 -1)
+ // See the unittest OutputConfiguratorTest.CTMForMultiScreens.
+ ctm.x_scale =
+ static_cast<float>(mode_info->width - 1) / (framebuffer_width - 1);
+ ctm.x_offset = static_cast<float>(output.x) / (framebuffer_width - 1);
+ ctm.y_scale =
+ static_cast<float>(mode_info->height - 1) / (framebuffer_height - 1);
+ ctm.y_offset = static_cast<float>(output.y) / (framebuffer_height - 1);
+ return ctm;
+}
+
float OutputConfigurator::GetMirroredDisplayAreaRatio(
const OutputConfigurator::OutputSnapshot& output) {
float area_ratio = 1.0f;
diff --git a/chromeos/display/output_configurator.h b/chromeos/display/output_configurator.h
index ef5085e..c927519 100644
--- a/chromeos/display/output_configurator.h
+++ b/chromeos/display/output_configurator.h
@@ -487,6 +487,15 @@ class CHROMEOS_EXPORT OutputConfigurator
CoordinateTransformation GetMirrorModeCTM(
const OutputConfigurator::OutputSnapshot& output);
+ // Computes the relevant transformation for extended mode.
+ // |output| is the output on which extended mode is being applied.
+ // |width| and |height| are the width and height of the combined framebuffer.
+ // Returns the transformation or identity if computations fail.
+ CoordinateTransformation GetExtendedModeCTM(
+ const OutputConfigurator::OutputSnapshot& output,
+ int framebuffer_width,
+ int frame_buffer_height);
+
// Returns the ratio between mirrored mode area and native mode area:
// (mirror_mode_width * mirrow_mode_height) / (native_width * native_height)
float GetMirroredDisplayAreaRatio(
diff --git a/chromeos/display/output_configurator_unittest.cc b/chromeos/display/output_configurator_unittest.cc
index 28f0553..571df38 100644
--- a/chromeos/display/output_configurator_unittest.cc
+++ b/chromeos/display/output_configurator_unittest.cc
@@ -4,6 +4,7 @@
#include "chromeos/display/output_configurator.h"
+#include <cmath>
#include <cstdarg>
#include <map>
#include <string>
@@ -128,6 +129,11 @@ class TestDelegate : public OutputConfigurator::Delegate {
return actions;
}
+ const OutputConfigurator::CoordinateTransformation& get_ctm(
+ int touch_device_id) {
+ return ctms_[touch_device_id];
+ }
+
// OutputConfigurator::Delegate overrides:
virtual void InitXRandRExtension(int* event_base) OVERRIDE {
AppendAction(kInitXRandR);
@@ -171,6 +177,7 @@ class TestDelegate : public OutputConfigurator::Delegate {
int touch_device_id,
const OutputConfigurator::CoordinateTransformation& ctm) OVERRIDE {
AppendAction(GetCTMAction(touch_device_id, ctm));
+ ctms_[touch_device_id] = ctm;
}
virtual void SendProjectingStateToPowerManager(bool projecting) OVERRIDE {
AppendAction(projecting ? kProjectingOn : kProjectingOff);
@@ -207,6 +214,9 @@ class TestDelegate : public OutputConfigurator::Delegate {
std::map<RRMode, ModeDetails> modes_;
+ // Most-recently-configured transformation matrices, keyed by touch device ID.
+ std::map<int, OutputConfigurator::CoordinateTransformation> ctms_;
+
// Outputs to be returned by GetOutputs().
std::vector<OutputConfigurator::OutputSnapshot> outputs_;
@@ -1223,4 +1233,34 @@ TEST_F(OutputConfiguratorTest, OutputProtectionTwoClients) {
delegate_->GetActionsAndClear());
}
+TEST_F(OutputConfiguratorTest, CTMForMultiScreens) {
+ outputs_[0].touch_device_id = 1;
+ outputs_[1].touch_device_id = 2;
+
+ UpdateOutputs(2, false);
+ configurator_.Init(false);
+ state_controller_.set_state(STATE_DUAL_EXTENDED);
+ configurator_.Start(0);
+
+ const int kDualHeight =
+ kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
+ const int kDualWidth = kBigModeWidth;
+
+ OutputConfigurator::CoordinateTransformation ctm1 = delegate_->get_ctm(1);
+ OutputConfigurator::CoordinateTransformation ctm2 = delegate_->get_ctm(2);
+
+ EXPECT_EQ(kSmallModeHeight - 1, round((kDualHeight - 1) * ctm1.y_scale));
+ EXPECT_EQ(0, round((kDualHeight - 1) * ctm1.y_offset));
+
+ EXPECT_EQ(kBigModeHeight - 1, round((kDualHeight - 1) * ctm2.y_scale));
+ EXPECT_EQ(kSmallModeHeight + OutputConfigurator::kVerticalGap,
+ round((kDualHeight - 1) * ctm2.y_offset));
+
+ EXPECT_EQ(kSmallModeWidth - 1, round((kDualWidth - 1) * ctm1.x_scale));
+ EXPECT_EQ(0, round((kDualWidth - 1) * ctm1.x_offset));
+
+ EXPECT_EQ(kBigModeWidth - 1, round((kDualWidth - 1) * ctm2.x_scale));
+ EXPECT_EQ(0, round((kDualWidth - 1) * ctm2.x_offset));
+}
+
} // namespace chromeos