Add touch events to the protocol, the stub layer, and to the client plugin.

- Add TouchEvent and TouchEventPoint messages to the input event protocol.
- Extend the InputStub interface with an InjectTouchEvent() method.
- Update InputEventTracker to track touch points, and to cancel them
  when ReleaseAll() is called.
- Implement touch handling in the client plugin, but off by default.
  The web-app may choose to enable touch handling if desired.
- Add a TouchInputScaler that scales and clamps touch points, similarly to
  the MouseInputFilter, for use by both client and host.

BUG=314515

Review URL: https://codereview.chromium.org/799233004

Cr-Commit-Position: refs/heads/master@{#318284}
diff --git a/remoting/protocol/input_event_tracker.cc b/remoting/protocol/input_event_tracker.cc
index 446a4b6..ff7c1df 100644
--- a/remoting/protocol/input_event_tracker.cc
+++ b/remoting/protocol/input_event_tracker.cc
@@ -26,15 +26,16 @@
 }
 
 void InputEventTracker::ReleaseAll() {
-  std::set<uint32>::iterator i;
-  for (i = pressed_keys_.begin(); i != pressed_keys_.end(); ++i) {
+  // Release all pressed keys.
+  for (uint32 keycode : pressed_keys_) {
     KeyEvent event;
     event.set_pressed(false);
-    event.set_usb_keycode(*i);
+    event.set_usb_keycode(keycode);
     input_stub_->InjectKeyEvent(event);
   }
   pressed_keys_.clear();
 
+  // Release all mouse buttons.
   for (int i = MouseEvent::BUTTON_UNDEFINED + 1;
        i < MouseEvent::BUTTON_MAX; ++i) {
     if (mouse_button_state_ & (1 << (i - 1))) {
@@ -51,6 +52,19 @@
     }
   }
   mouse_button_state_ = 0;
+
+  // Cancel all active touch points.
+  if (!touch_point_ids_.empty()) {
+    TouchEvent cancel_all_touch_event;
+    cancel_all_touch_event.set_event_type(TouchEvent::TOUCH_POINT_CANCEL);
+    for (uint32 touch_point_id : touch_point_ids_) {
+      TouchEventPoint* point = cancel_all_touch_event.add_touch_points();
+      point->set_id(touch_point_id);
+    }
+    input_stub_->InjectTouchEvent(cancel_all_touch_event);
+    touch_point_ids_.clear();
+  }
+  DCHECK(touch_point_ids_.empty());
 }
 
 void InputEventTracker::InjectKeyEvent(const KeyEvent& event) {
@@ -92,5 +106,31 @@
   input_stub_->InjectMouseEvent(event);
 }
 
+void InputEventTracker::InjectTouchEvent(const TouchEvent& event) {
+  // We only need the IDs to cancel all touch points in ReleaseAll(). Other
+  // fields do not have to be tracked here as long as the host keeps track of
+  // them.
+  switch (event.event_type()) {
+    case TouchEvent::TOUCH_POINT_START:
+      for (const TouchEventPoint& touch_point : event.touch_points()) {
+        DCHECK(touch_point_ids_.find(touch_point.id()) ==
+               touch_point_ids_.end());
+        touch_point_ids_.insert(touch_point.id());
+      }
+      break;
+    case TouchEvent::TOUCH_POINT_END:
+    case TouchEvent::TOUCH_POINT_CANCEL:
+      for (const TouchEventPoint& touch_point : event.touch_points()) {
+        DCHECK(touch_point_ids_.find(touch_point.id()) !=
+               touch_point_ids_.end());
+        touch_point_ids_.erase(touch_point.id());
+      }
+      break;
+    default:
+      break;
+  }
+  input_stub_->InjectTouchEvent(event);
+}
+
 }  // namespace protocol
 }  // namespace remoting