| Index: remoting/client/plugin/touch_input_scaler.cc | 
| diff --git a/remoting/client/plugin/touch_input_scaler.cc b/remoting/client/plugin/touch_input_scaler.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..11396ab931cce35003e79f87962b8b0d3abeb0c3 | 
| --- /dev/null | 
| +++ b/remoting/client/plugin/touch_input_scaler.cc | 
| @@ -0,0 +1,86 @@ | 
| +// Copyright 2015 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 "remoting/client/plugin/touch_input_scaler.h" | 
| + | 
| +#include "base/logging.h" | 
| +#include "remoting/proto/event.pb.h" | 
| + | 
| +namespace remoting { | 
| + | 
| +using protocol::TouchEvent; | 
| +using protocol::TouchEventPoint; | 
| + | 
| +namespace { | 
| + | 
| +// |value| is the number to be scaled. |output_max| is the output desktop's max | 
| +// height or width. |input_max| is the input desktop's max height or width. | 
| +float Scale(float value, int output_max, int input_max) { | 
| +  DCHECK_GT(output_max, 0); | 
| +  DCHECK_GT(input_max, 0); | 
| +  value *= output_max; | 
| +  value /= input_max; | 
| +  return value; | 
| +} | 
| + | 
| +// Same as Scale() but |value| will be scaled and clamped using |output_max| and | 
| +// |input_max|. | 
| +float ScaleAndClamp(float value, int output_max, int input_max) { | 
| +  value = Scale(value, output_max, input_max); | 
| +  return std::max(0.0f, std::min(static_cast<float>(output_max), value)); | 
| +} | 
| + | 
| +}  // namespace | 
| + | 
| +TouchInputScaler::TouchInputScaler(InputStub* input_stub) | 
| +    : InputFilter(input_stub) {} | 
| + | 
| +TouchInputScaler::~TouchInputScaler() {} | 
| + | 
| +void TouchInputScaler::InjectTouchEvent(const TouchEvent& event) { | 
| +  if (input_size_.is_empty() || output_size_.is_empty()) | 
| +    return; | 
| + | 
| +  // We scale based on the maximum input & output coordinates, rather than the | 
| +  // input and output sizes, so that it's possible to reach the edge of the | 
| +  // output when up-scaling.  We also take care to round up or down correctly, | 
| +  // which is important when down-scaling. | 
| +  TouchEvent out_event(event); | 
| +  for (int i = 0; i < out_event.touch_points().size(); ++i) { | 
| +    TouchEventPoint* point = out_event.mutable_touch_points(i); | 
| +    if (point->has_x() || point->has_y()) { | 
| +      DCHECK(point->has_x() && point->has_y()); | 
| +      point->set_x( | 
| +          ScaleAndClamp(point->x(), output_size_.width(), input_size_.width())); | 
| +      point->set_y(ScaleAndClamp(point->y(), output_size_.height(), | 
| +                                 input_size_.height())); | 
| +    } | 
| + | 
| +    // Also scale the touch size. Without scaling, the size on the host will not | 
| +    // be right. | 
| +    // For example | 
| +    // Suppose: | 
| +    //  - No size scaling. | 
| +    //  - Client is a HiDPI Chromebook device. | 
| +    //  - Host is running on a HiDPI Windows device. | 
| +    // With the configuration above, the client will send the logical touch | 
| +    // size to the host, therefore it will be smaller on the host. | 
| +    // This is because a HiDPI Chromebook device (e.g. Pixel) has 2 by 2 | 
| +    // physical pixel mapped to a logical pixel. | 
| +    // With scaling, the size would be the same. | 
| +    // TODO(rkuroiwa): Also clamp. Note that point->angle() affects the maximum | 
| +    // size (crbug.com/461526). | 
| +    if (point->has_radius_x() || point->has_radius_y()) { | 
| +      DCHECK(point->has_radius_x() && point->has_radius_y()); | 
| +      point->set_radius_x( | 
| +          Scale(point->radius_x(), output_size_.width(), input_size_.width())); | 
| +      point->set_radius_y(Scale(point->radius_y(), output_size_.height(), | 
| +                                input_size_.height())); | 
| +    } | 
| +  } | 
| + | 
| +  InputFilter::InjectTouchEvent(out_event); | 
| +} | 
| + | 
| +}  // namespace remoting | 
|  |