blob: 547314c8a27570dec232d8dc52d28195b5f498f1 [file] [log] [blame]
// 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/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.
// Note that there's no need to clamp the touch point size. For example on
// a Nexus4 device, part of the touch circle falls outside the screen on
// edges but still functions correctly.
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