Make LatencyInfo to be class

LatencyInfo has grown to be more than a pure data holder
struct. Make it a class so that we have a clean API
surface that can access/modify the data members.

BUG=None
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

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

Cr-Commit-Position: refs/heads/master@{#341831}
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index 3401eceb..4852bdc 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -19,7 +19,9 @@
 class Vector2dF;
 }
 
-namespace ui { struct LatencyInfo; }
+namespace ui {
+class LatencyInfo;
+}
 
 namespace cc {
 
diff --git a/cc/output/latency_info_swap_promise.cc b/cc/output/latency_info_swap_promise.cc
index 5e08470..8b3fc49 100644
--- a/cc/output/latency_info_swap_promise.cc
+++ b/cc/output/latency_info_swap_promise.cc
@@ -34,7 +34,7 @@
 }
 
 void LatencyInfoSwapPromise::DidSwap(CompositorFrameMetadata* metadata) {
-  DCHECK(!latency_.terminated);
+  DCHECK(!latency_.terminated());
   metadata->latency_info.push_back(latency_);
 }
 
@@ -47,7 +47,7 @@
 }
 
 int64 LatencyInfoSwapPromise::TraceId() const {
-  return latency_.trace_id;
+  return latency_.trace_id();
 }
 
 // Trace the original LatencyInfo of a LatencyInfoSwapPromise
diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h
index 423dc631..7d0a5d9 100644
--- a/cc/output/output_surface.h
+++ b/cc/output/output_surface.h
@@ -18,7 +18,9 @@
 
 namespace base { class SingleThreadTaskRunner; }
 
-namespace ui { struct LatencyInfo; }
+namespace ui {
+class LatencyInfo;
+}
 
 namespace gfx {
 class Rect;
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index 2b6e132..7e80854 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -227,11 +227,9 @@
   if (should_swap) {
     swapped_since_resize_ = true;
     for (auto& latency : frame->metadata.latency_info) {
-      TRACE_EVENT_FLOW_STEP0(
-          "input,benchmark",
-          "LatencyInfo.Flow",
-          TRACE_ID_DONT_MANGLE(latency.trace_id),
-          "Display::DrawAndSwap");
+      TRACE_EVENT_FLOW_STEP0("input,benchmark", "LatencyInfo.Flow",
+                             TRACE_ID_DONT_MANGLE(latency.trace_id()),
+                             "Display::DrawAndSwap");
     }
     benchmark_instrumentation::IssueDisplayRenderingStatsEvent();
     renderer_->SwapBuffers(frame->metadata);
diff --git a/cc/surfaces/surface.h b/cc/surfaces/surface.h
index d9099f3..8ef332e 100644
--- a/cc/surfaces/surface.h
+++ b/cc/surfaces/surface.h
@@ -23,7 +23,7 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace ui {
-struct LatencyInfo;
+class LatencyInfo;
 }
 
 namespace cc {
diff --git a/cc/trees/latency_info_swap_promise_monitor.cc b/cc/trees/latency_info_swap_promise_monitor.cc
index c63ac5b..6e9c57e 100644
--- a/cc/trees/latency_info_swap_promise_monitor.cc
+++ b/cc/trees/latency_info_swap_promise_monitor.cc
@@ -30,7 +30,7 @@
     return false;
   latency_info->AddLatencyNumber(
       ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT, 0,
-      latency_info->trace_id);
+      latency_info->trace_id());
   return true;
 }
 
@@ -67,8 +67,8 @@
   if (AddForwardingScrollUpdateToMainComponent(latency_)) {
     int64 new_sequence_number = 0;
     for (ui::LatencyInfo::LatencyMap::const_iterator it =
-             latency_->latency_components.begin();
-         it != latency_->latency_components.end(); ++it) {
+             latency_->latency_components().begin();
+         it != latency_->latency_components().end(); ++it) {
       if (it->first.first == ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT) {
         new_sequence_number =
             ((static_cast<int64>(base::PlatformThread::CurrentId()) << 32) ^
diff --git a/cc/trees/latency_info_swap_promise_monitor.h b/cc/trees/latency_info_swap_promise_monitor.h
index c1d9973..2f5e0e5 100644
--- a/cc/trees/latency_info_swap_promise_monitor.h
+++ b/cc/trees/latency_info_swap_promise_monitor.h
@@ -9,7 +9,7 @@
 #define CC_TREES_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_
 
 namespace ui {
-struct LatencyInfo;
+class LatencyInfo;
 }  // namespace ui
 
 namespace cc {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 6a9207bf..ae0c943 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1742,11 +1742,9 @@
   CompositorFrameMetadata metadata = MakeCompositorFrameMetadata();
   active_tree()->FinishSwapPromises(&metadata);
   for (auto& latency : metadata.latency_info) {
-    TRACE_EVENT_FLOW_STEP0(
-        "input,benchmark",
-        "LatencyInfo.Flow",
-        TRACE_ID_DONT_MANGLE(latency.trace_id),
-        "SwapBuffers");
+    TRACE_EVENT_FLOW_STEP0("input,benchmark", "LatencyInfo.Flow",
+                           TRACE_ID_DONT_MANGLE(latency.trace_id()),
+                           "SwapBuffers");
     // Only add the latency component once for renderer swap, not the browser
     // swap.
     if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT,
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 03c02e77..3c39a2a 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -1369,7 +1369,8 @@
 
 TEST_F(LayerTreeHostImplTest, ScrollWithSwapPromises) {
   ui::LatencyInfo latency_info;
-  latency_info.trace_id = 1234;
+  latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0,
+                                1234);
   scoped_ptr<SwapPromise> swap_promise(
       new LatencyInfoSwapPromise(latency_info));
 
@@ -1382,7 +1383,7 @@
 
   scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
   EXPECT_EQ(1u, scroll_info->swap_promises.size());
-  EXPECT_EQ(latency_info.trace_id, scroll_info->swap_promises[0]->TraceId());
+  EXPECT_EQ(latency_info.trace_id(), scroll_info->swap_promises[0]->TraceId());
 }
 
 // Test that scrolls targeting a layer with a non-null scroll_parent() bubble
diff --git a/content/browser/gpu/gpu_process_host_ui_shim.h b/content/browser/gpu/gpu_process_host_ui_shim.h
index 598fd5a9..184ecbc 100644
--- a/content/browser/gpu/gpu_process_host_ui_shim.h
+++ b/content/browser/gpu/gpu_process_host_ui_shim.h
@@ -29,7 +29,7 @@
 #endif
 
 namespace ui {
-struct LatencyInfo;
+class LatencyInfo;
 }
 
 namespace gfx {
diff --git a/content/browser/renderer_host/event_with_latency_info.h b/content/browser/renderer_host/event_with_latency_info.h
index 37f6747..93e4ecd 100644
--- a/content/browser/renderer_host/event_with_latency_info.h
+++ b/content/browser/renderer_host/event_with_latency_info.h
@@ -41,8 +41,9 @@
     // When coalescing two input events, we keep the oldest LatencyInfo
     // for Telemetry latency test since it will represent the longest
     // latency.
-    if (other.latency.trace_id >= 0 &&
-        (latency.trace_id < 0 || other.latency.trace_id < latency.trace_id))
+    if (other.latency.trace_id() >= 0 &&
+        (latency.trace_id() < 0 ||
+         other.latency.trace_id() < latency.trace_id()))
       latency = other.latency;
   }
 };
diff --git a/content/browser/renderer_host/input/gesture_event_queue.cc b/content/browser/renderer_host/input/gesture_event_queue.cc
index a13fde1..c52bbdb5 100644
--- a/content/browser/renderer_host/input/gesture_event_queue.cc
+++ b/content/browser/renderer_host/input/gesture_event_queue.cc
@@ -335,7 +335,7 @@
   scroll_event.event.sourceDevice = gesture_event.event.sourceDevice;
   scroll_event.event.timeStampSeconds = gesture_event.event.timeStampSeconds;
   // Keep the oldest LatencyInfo.
-  DCHECK_LE(last_event->latency.trace_id, gesture_event.latency.trace_id);
+  DCHECK_LE(last_event->latency.trace_id(), gesture_event.latency.trace_id());
   scroll_event.latency = last_event->latency;
   pinch_event = scroll_event;
   scroll_event.event.type = WebInputEvent::GestureScrollUpdate;
@@ -355,8 +355,8 @@
         coalesced_gesture_events_[coalesced_gesture_events_.size() - 2];
     if (IsCompatibleScrollorPinch(gesture_event, second_last_event)) {
       // Keep the oldest LatencyInfo.
-      DCHECK_LE(second_last_event.latency.trace_id,
-                scroll_event.latency.trace_id);
+      DCHECK_LE(second_last_event.latency.trace_id(),
+                scroll_event.latency.trace_id());
       scroll_event.latency = second_last_event.latency;
       pinch_event.latency = second_last_event.latency;
       combined_scroll_pinch.PreconcatTransform(
diff --git a/content/browser/renderer_host/input/input_router_client.h b/content/browser/renderer_host/input/input_router_client.h
index dd3c6a0a..34fdf0eb 100644
--- a/content/browser/renderer_host/input/input_router_client.h
+++ b/content/browser/renderer_host/input/input_router_client.h
@@ -12,7 +12,7 @@
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 
 namespace ui {
-struct LatencyInfo;
+class LatencyInfo;
 }
 
 namespace content {
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h
index e7c84a9..560596b 100644
--- a/content/browser/renderer_host/input/input_router_impl.h
+++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -23,7 +23,7 @@
 }
 
 namespace ui {
-struct LatencyInfo;
+class LatencyInfo;
 }
 
 namespace content {
diff --git a/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc b/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
index c7d1c6d..1cf6498 100644
--- a/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
+++ b/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
@@ -18,37 +18,40 @@
 namespace content {
 namespace {
 
-const uint32 kMaxInputCoordinates = LatencyInfo::kMaxInputCoordinates;
-
 void UpdateLatencyCoordinatesImpl(const blink::WebTouchEvent& touch,
-                                  LatencyInfo* latency) {
-  latency->input_coordinates_size =
-      std::min(kMaxInputCoordinates, touch.touchesLength);
-  for (uint32 i = 0; i < latency->input_coordinates_size; ++i) {
-    latency->input_coordinates[i] = LatencyInfo::InputCoordinate(
-        touch.touches[i].position.x, touch.touches[i].position.y);
+                                  LatencyInfo* latency,
+                                  float device_scale_factor) {
+  for (uint32 i = 0; i < touch.touchesLength; ++i) {
+    LatencyInfo::InputCoordinate coordinate(
+        touch.touches[i].position.x * device_scale_factor,
+        touch.touches[i].position.y * device_scale_factor);
+    if (!latency->AddInputCoordinate(coordinate))
+      break;
   }
 }
 
 void UpdateLatencyCoordinatesImpl(const WebGestureEvent& gesture,
-                                  LatencyInfo* latency) {
-  latency->input_coordinates_size = 1;
-  latency->input_coordinates[0] =
-      LatencyInfo::InputCoordinate(gesture.x, gesture.y);
+                                  LatencyInfo* latency,
+                                  float device_scale_factor) {
+  latency->AddInputCoordinate(
+      LatencyInfo::InputCoordinate(gesture.x * device_scale_factor,
+                                   gesture.y * device_scale_factor));
 }
 
 void UpdateLatencyCoordinatesImpl(const WebMouseEvent& mouse,
-                                  LatencyInfo* latency) {
-  latency->input_coordinates_size = 1;
-  latency->input_coordinates[0] =
-      LatencyInfo::InputCoordinate(mouse.x, mouse.y);
+                                  LatencyInfo* latency,
+                                  float device_scale_factor) {
+  latency->AddInputCoordinate(
+      LatencyInfo::InputCoordinate(mouse.x * device_scale_factor,
+                                   mouse.y * device_scale_factor));
 }
 
 void UpdateLatencyCoordinatesImpl(const WebMouseWheelEvent& wheel,
-                                  LatencyInfo* latency) {
-  latency->input_coordinates_size = 1;
-  latency->input_coordinates[0] =
-      LatencyInfo::InputCoordinate(wheel.x, wheel.y);
+                                  LatencyInfo* latency,
+                                  float device_scale_factor) {
+  latency->AddInputCoordinate(
+      LatencyInfo::InputCoordinate(wheel.x * device_scale_factor,
+                                   wheel.y * device_scale_factor));
 }
 
 void UpdateLatencyCoordinates(const WebInputEvent& event,
@@ -56,22 +59,16 @@
                               LatencyInfo* latency) {
   if (WebInputEvent::isMouseEventType(event.type)) {
     UpdateLatencyCoordinatesImpl(static_cast<const WebMouseEvent&>(event),
-                                 latency);
+                                 latency, device_scale_factor);
   } else if (WebInputEvent::isGestureEventType(event.type)) {
     UpdateLatencyCoordinatesImpl(static_cast<const WebGestureEvent&>(event),
-                                 latency);
+                                 latency, device_scale_factor);
   } else if (WebInputEvent::isTouchEventType(event.type)) {
     UpdateLatencyCoordinatesImpl(static_cast<const WebTouchEvent&>(event),
-                                 latency);
+                                 latency, device_scale_factor);
   } else if (event.type == WebInputEvent::MouseWheel) {
     UpdateLatencyCoordinatesImpl(static_cast<const WebMouseWheelEvent&>(event),
-                                 latency);
-  }
-  if (device_scale_factor == 1)
-    return;
-  for (uint32 i = 0; i < latency->input_coordinates_size; ++i) {
-    latency->input_coordinates[i].x *= device_scale_factor;
-    latency->input_coordinates[i].y *= device_scale_factor;
+                                 latency, device_scale_factor);
   }
 }
 
@@ -260,25 +257,29 @@
 // component ID where necessary.
 void AddLatencyInfoComponentIds(LatencyInfo* latency,
                                 int64 latency_component_id) {
-  LatencyInfo::LatencyMap new_components;
-  auto lc = latency->latency_components.begin();
-  while (lc != latency->latency_components.end()) {
-    ui::LatencyComponentType component_type = lc->first.first;
+  std::vector<std::pair<ui::LatencyComponentType, int64>> new_components_key;
+  std::vector<LatencyInfo::LatencyComponent> new_components_value;
+  for (const auto& lc : latency->latency_components()) {
+    ui::LatencyComponentType component_type = lc.first.first;
     if (component_type == ui::WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT) {
       // Generate a new component entry with the correct component ID
-      auto key = std::make_pair(component_type, latency_component_id);
-      new_components[key] = lc->second;
-
-      // Remove the old entry
-      latency->latency_components.erase(lc++);
-    } else {
-      ++lc;
+      new_components_key.push_back(std::make_pair(component_type,
+                                                  latency_component_id));
+      new_components_value.push_back(lc.second);
     }
   }
 
+  // Remove the entries with invalid component IDs.
+  latency->RemoveLatency(ui::WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT);
+
   // Add newly generated components into the latency info
-  for (lc = new_components.begin(); lc != new_components.end(); ++lc) {
-    latency->latency_components[lc->first] = lc->second;
+  for (size_t i = 0; i < new_components_key.size(); i++) {
+    latency->AddLatencyNumberWithTimestamp(
+        new_components_key[i].first,
+        new_components_key[i].second,
+        new_components_value[i].sequence_number,
+        new_components_value[i].event_time,
+        new_components_value[i].event_count);
   }
 }
 
diff --git a/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc b/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
index 3db8365..be6e2a90 100644
--- a/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
+++ b/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
@@ -34,7 +34,7 @@
     EXPECT_TRUE(
         scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
                                    0, nullptr));
-    EXPECT_EQ(1U, scroll_latency.input_coordinates_size);
+    EXPECT_EQ(1U, scroll_latency.input_coordinates_size());
   }
 
   {
@@ -50,7 +50,7 @@
     EXPECT_TRUE(
         wheel_latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
                                    0, nullptr));
-    EXPECT_EQ(1U, wheel_latency.input_coordinates_size);
+    EXPECT_EQ(1U, wheel_latency.input_coordinates_size());
   }
 
   {
@@ -65,7 +65,7 @@
     EXPECT_TRUE(
         touch_latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
                                    0, nullptr));
-    EXPECT_EQ(2U, touch_latency.input_coordinates_size);
+    EXPECT_EQ(2U, touch_latency.input_coordinates_size());
   }
 }
 
@@ -81,7 +81,7 @@
     tracker.OnInputEventAck(scroll, &scroll_latency);
     EXPECT_TRUE(scroll_latency.FindLatency(
         ui::INPUT_EVENT_LATENCY_TERMINATED_GESTURE_COMPONENT, 0, nullptr));
-    EXPECT_TRUE(scroll_latency.terminated);
+    EXPECT_TRUE(scroll_latency.terminated());
   }
 
   {
@@ -92,7 +92,7 @@
     tracker.OnInputEventAck(wheel, &wheel_latency);
     EXPECT_TRUE(wheel_latency.FindLatency(
         ui::INPUT_EVENT_LATENCY_TERMINATED_MOUSE_COMPONENT, 0, nullptr));
-    EXPECT_TRUE(wheel_latency.terminated);
+    EXPECT_TRUE(wheel_latency.terminated());
   }
 
   {
@@ -103,7 +103,7 @@
     tracker.OnInputEventAck(touch, &touch_latency);
     EXPECT_TRUE(touch_latency.FindLatency(
         ui::INPUT_EVENT_LATENCY_TERMINATED_TOUCH_COMPONENT, 0, nullptr));
-    EXPECT_TRUE(touch_latency.terminated);
+    EXPECT_TRUE(touch_latency.terminated());
   }
 }
 
@@ -117,9 +117,9 @@
     event.y = 200;
     ui::LatencyInfo latency_info;
     tracker.OnInputEvent(event, &latency_info);
-    EXPECT_EQ(1u, latency_info.input_coordinates_size);
-    EXPECT_EQ(100, latency_info.input_coordinates[0].x);
-    EXPECT_EQ(200, latency_info.input_coordinates[0].y);
+    EXPECT_EQ(1u, latency_info.input_coordinates_size());
+    EXPECT_EQ(100, latency_info.input_coordinates()[0].x);
+    EXPECT_EQ(200, latency_info.input_coordinates()[0].y);
   }
 
   {
@@ -128,9 +128,9 @@
     event.y = 400;
     ui::LatencyInfo latency_info;
     tracker.OnInputEvent(event, &latency_info);
-    EXPECT_EQ(1u, latency_info.input_coordinates_size);
-    EXPECT_EQ(300, latency_info.input_coordinates[0].x);
-    EXPECT_EQ(400, latency_info.input_coordinates[0].y);
+    EXPECT_EQ(1u, latency_info.input_coordinates_size());
+    EXPECT_EQ(300, latency_info.input_coordinates()[0].x);
+    EXPECT_EQ(400, latency_info.input_coordinates()[0].y);
   }
 
   {
@@ -140,9 +140,9 @@
     event.y = 600;
     ui::LatencyInfo latency_info;
     tracker.OnInputEvent(event, &latency_info);
-    EXPECT_EQ(1u, latency_info.input_coordinates_size);
-    EXPECT_EQ(500, latency_info.input_coordinates[0].x);
-    EXPECT_EQ(600, latency_info.input_coordinates[0].y);
+    EXPECT_EQ(1u, latency_info.input_coordinates_size());
+    EXPECT_EQ(500, latency_info.input_coordinates()[0].x);
+    EXPECT_EQ(600, latency_info.input_coordinates()[0].y);
   }
 
   {
@@ -152,11 +152,11 @@
     event.PressPoint(1100, 1200);  // LatencyInfo only holds two coordinates.
     ui::LatencyInfo latency_info;
     tracker.OnInputEvent(event, &latency_info);
-    EXPECT_EQ(2u, latency_info.input_coordinates_size);
-    EXPECT_EQ(700, latency_info.input_coordinates[0].x);
-    EXPECT_EQ(800, latency_info.input_coordinates[0].y);
-    EXPECT_EQ(900, latency_info.input_coordinates[1].x);
-    EXPECT_EQ(1000, latency_info.input_coordinates[1].y);
+    EXPECT_EQ(2u, latency_info.input_coordinates_size());
+    EXPECT_EQ(700, latency_info.input_coordinates()[0].x);
+    EXPECT_EQ(800, latency_info.input_coordinates()[0].y);
+    EXPECT_EQ(900, latency_info.input_coordinates()[1].x);
+    EXPECT_EQ(1000, latency_info.input_coordinates()[1].y);
   }
 
   {
@@ -164,7 +164,7 @@
     event.type = blink::WebKeyboardEvent::KeyDown;
     ui::LatencyInfo latency_info;
     tracker.OnInputEvent(event, &latency_info);
-    EXPECT_EQ(0u, latency_info.input_coordinates_size);
+    EXPECT_EQ(0u, latency_info.input_coordinates_size());
   }
 }
 
@@ -180,7 +180,7 @@
   EXPECT_TRUE(
       scroll_latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
                                  tracker.latency_component_id(), nullptr));
-  EXPECT_EQ(2U, scroll_latency.latency_components.size());
+  EXPECT_EQ(2U, scroll_latency.latency_components().size());
 
   // The first GestureScrollUpdate should be provided with
   // INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT.
@@ -199,7 +199,7 @@
   EXPECT_FALSE(scroll_latency.FindLatency(
       ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
       tracker.latency_component_id(), nullptr));
-  EXPECT_EQ(3U, scroll_latency.latency_components.size());
+  EXPECT_EQ(3U, scroll_latency.latency_components().size());
 
   // Subseqeunt GestureScrollUpdates should be provided with
   // INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT.
@@ -218,7 +218,7 @@
   EXPECT_TRUE(scroll_latency.FindLatency(
       ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
       tracker.latency_component_id(), nullptr));
-  EXPECT_EQ(3U, scroll_latency.latency_components.size());
+  EXPECT_EQ(3U, scroll_latency.latency_components().size());
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_base.h b/content/browser/renderer_host/input/synthetic_gesture_target_base.h
index d48be11..8063ae0 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_base.h
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_base.h
@@ -9,7 +9,7 @@
 #include "content/browser/renderer_host/input/synthetic_gesture_target.h"
 
 namespace ui {
-struct LatencyInfo;
+class LatencyInfo;
 }
 
 namespace blink {
diff --git a/content/browser/renderer_host/overscroll_controller.h b/content/browser/renderer_host/overscroll_controller.h
index 04a959101..6ea77e60 100644
--- a/content/browser/renderer_host/overscroll_controller.h
+++ b/content/browser/renderer_host/overscroll_controller.h
@@ -10,7 +10,7 @@
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 
 namespace ui {
-struct LatencyInfo;
+class LatencyInfo;
 }
 
 namespace content {
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 004ea6f..6c78dff 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2046,16 +2046,13 @@
     const std::vector<ui::LatencyInfo>& latency_info) {
   for (size_t i = 0; i < latency_info.size(); i++) {
     std::set<RenderWidgetHostImpl*> rwhi_set;
-    for (ui::LatencyInfo::LatencyMap::const_iterator b =
-             latency_info[i].latency_components.begin();
-         b != latency_info[i].latency_components.end();
-         ++b) {
-      if (b->first.first == ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT ||
-          b->first.first == ui::WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT ||
-          b->first.first == ui::TAB_SHOW_COMPONENT) {
+    for (const auto& lc : latency_info[i].latency_components()) {
+      if (lc.first.first == ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT ||
+          lc.first.first == ui::WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT ||
+          lc.first.first == ui::TAB_SHOW_COMPONENT) {
         // Matches with GetLatencyComponentId
-        int routing_id = b->first.second & 0xffffffff;
-        int process_id = (b->first.second >> 32) & 0xffffffff;
+        int routing_id = lc.first.second & 0xffffffff;
+        int process_id = (lc.first.second >> 32) & 0xffffffff;
         RenderWidgetHost* rwh =
             RenderWidgetHost::FromID(process_id, routing_id);
         if (!rwh) {
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 9187f51d..1683f01 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -156,7 +156,7 @@
     "//ui/accessibility",
     "//ui/base",
     "//ui/base/ime",
-    "//ui/events/ipc",
+    "//ui/events/ipc:events_ipc",
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/gfx/ipc",
diff --git a/content/common/input/input_param_traits_unittest.cc b/content/common/input/input_param_traits_unittest.cc
index f40152f..784278a 100644
--- a/content/common/input/input_param_traits_unittest.cc
+++ b/content/common/input/input_param_traits_unittest.cc
@@ -28,8 +28,8 @@
       ASSERT_EQ(a_size, b->web_event->size);
       EXPECT_EQ(0, memcmp(a->web_event.get(), b->web_event.get(), a_size));
     }
-    EXPECT_EQ(a->latency_info.latency_components.size(),
-              b->latency_info.latency_components.size());
+    EXPECT_EQ(a->latency_info.latency_components().size(),
+              b->latency_info.latency_components().size());
     EXPECT_EQ(a->is_keyboard_shortcut, b->is_keyboard_shortcut);
   }
 
diff --git a/content/content_common.gypi b/content/content_common.gypi
index a46dd3a..586c389 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -15,7 +15,7 @@
     '../ui/accessibility/accessibility.gyp:ax_gen',
     '../ui/base/ime/ui_base_ime.gyp:ui_base_ime',
     '../ui/base/ui_base.gyp:ui_base',
-    '../ui/events/ipc/events_ipc.gyp:events_ipc',
+    '../ui/events/events.gyp:events_ipc',
     '../ui/gfx/gfx.gyp:gfx',
     '../ui/gfx/gfx.gyp:gfx_geometry',
     '../ui/gfx/ipc/gfx_ipc.gyp:gfx_ipc',
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index 52dbf6e..185ac08 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -22,7 +22,7 @@
 #include "ui/gfx/geometry/rect.h"
 
 namespace ui {
-struct LatencyInfo;
+class LatencyInfo;
 }
 
 namespace cc {
diff --git a/content/renderer/idle_user_detector.h b/content/renderer/idle_user_detector.h
index 86a7eac6..054ead8 100644
--- a/content/renderer/idle_user_detector.h
+++ b/content/renderer/idle_user_detector.h
@@ -13,7 +13,7 @@
 }
 
 namespace ui {
-struct LatencyInfo;
+class LatencyInfo;
 }
 
 namespace content {
diff --git a/content/renderer/input/input_handler_manager_client.h b/content/renderer/input/input_handler_manager_client.h
index a5c4cf2..8967881 100644
--- a/content/renderer/input/input_handler_manager_client.h
+++ b/content/renderer/input/input_handler_manager_client.h
@@ -12,7 +12,7 @@
 #include "ui/gfx/geometry/vector2d_f.h"
 
 namespace ui {
-struct LatencyInfo;
+class LatencyInfo;
 }
 
 namespace cc {
diff --git a/content/renderer/input/input_handler_proxy.cc b/content/renderer/input/input_handler_proxy.cc
index 232d8b7..cee5278 100644
--- a/content/renderer/input/input_handler_proxy.cc
+++ b/content/renderer/input/input_handler_proxy.cc
@@ -128,10 +128,10 @@
   }
 
   ui::LatencyInfo::LatencyMap::const_iterator it =
-      latency_info.latency_components.find(std::make_pair(
+      latency_info.latency_components().find(std::make_pair(
           ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0));
 
-  if (it == latency_info.latency_components.end())
+  if (it == latency_info.latency_components().end())
     return;
 
   base::TimeDelta delta = base::TimeTicks::Now() - it->second.event_time;
@@ -220,7 +220,7 @@
 
   TRACE_EVENT_FLOW_STEP0("input,benchmark",
                          "LatencyInfo.Flow",
-                         TRACE_ID_DONT_MANGLE(latency_info->trace_id),
+                         TRACE_ID_DONT_MANGLE(latency_info->trace_id()),
                          "HandleInputEventImpl");
 
   scoped_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor =
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 1bd3606..9c802bf 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -1121,7 +1121,7 @@
   TRACE_EVENT_FLOW_STEP0(
       "input,benchmark",
       "LatencyInfo.Flow",
-      TRACE_ID_DONT_MANGLE(latency_info.trace_id),
+      TRACE_ID_DONT_MANGLE(latency_info.trace_id()),
       "HanldeInputEventMain");
 
   // If we don't have a high res timer, these metrics won't be accurate enough
diff --git a/ppapi/proxy/BUILD.gn b/ppapi/proxy/BUILD.gn
index ffd0561..ffec0dbc 100644
--- a/ppapi/proxy/BUILD.gn
+++ b/ppapi/proxy/BUILD.gn
@@ -341,10 +341,7 @@
     "//ppapi/shared_impl",
   ]
   if (!is_nacl) {
-    deps += [
-      "//skia",
-      "//ui/events/ipc",
-    ]
+    deps += [ "//skia" ]
   }
 }
 
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index 0346346..7c4166f 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -58,10 +58,10 @@
 
 class Compositor;
 class CompositorVSyncManager;
+class LatencyInfo;
 class Layer;
 class Reflector;
 class Texture;
-struct LatencyInfo;
 
 const int kCompositorLockTimeoutMs = 67;
 
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index 58fdaea..6b45bb9 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -323,6 +323,7 @@
     "gesture_detection/touch_disposition_gesture_filter_unittest.cc",
     "gesture_detection/velocity_tracker_unittest.cc",
     "gestures/fling_curve_unittest.cc",
+    "ipc/latency_info_param_traits_unittest.cc",
     "keycodes/dom/keycode_converter_unittest.cc",
     "keycodes/keyboard_code_conversion_unittest.cc",
     "latency_info_unittest.cc",
@@ -337,9 +338,11 @@
     ":test_support",
     "//base",
     "//base/test:run_all_unittests",
+    "//ipc:test_support",
     "//skia",
     "//testing/gtest",
     "//ui/events/devices",
+    "//ui/events/ipc:events_ipc",
     "//ui/events/platform",
     "//ui/gfx:test_support",
   ]
diff --git a/ui/events/events.gyp b/ui/events/events.gyp
index 7dacf3af7..22dfaec 100644
--- a/ui/events/events.gyp
+++ b/ui/events/events.gyp
@@ -291,6 +291,23 @@
       ],
     },
     {
+      # GN version: //ui/events/ipc:events_ipc
+      'target_name': 'events_ipc',
+      'type': '<(component)',
+      'dependencies': [
+        '<(DEPTH)/base/base.gyp:base',
+        '<(DEPTH)/ipc/ipc.gyp:ipc',
+        'events_base',
+      ],
+      'defines': [
+        'EVENTS_IPC_IMPLEMENTATION',
+      ],
+      'sources': [
+        'ipc/latency_info_param_traits.cc',
+        'ipc/latency_info_param_traits.h',
+      ],
+    },
+    {
       # GN version: //ui/events:test_support
       'target_name': 'events_test_support',
       'type': 'static_library',
@@ -354,6 +371,7 @@
         '<(DEPTH)/base/base.gyp:base',
         '<(DEPTH)/base/base.gyp:run_all_unittests',
         '<(DEPTH)/base/base.gyp:test_support_base',
+        '<(DEPTH)/ipc/ipc.gyp:test_support_ipc',
         '<(DEPTH)/skia/skia.gyp:skia',
         '<(DEPTH)/testing/gtest.gyp:gtest',
         '<(DEPTH)/third_party/mesa/mesa.gyp:osmesa',
@@ -364,6 +382,7 @@
         'dom_keycode_converter',
         'events',
         'events_base',
+        'events_ipc',
         'events_test_support',
         'gesture_detection',
         'gestures_blink',
@@ -391,6 +410,7 @@
         'gestures/fling_curve_unittest.cc',
         'gestures/gesture_provider_aura_unittest.cc',
         'gestures/motion_event_aura_unittest.cc',
+        'ipc/latency_info_param_traits_unittest.cc',
         'keycodes/dom/keycode_converter_unittest.cc',
         'keycodes/keyboard_code_conversion_unittest.cc',
         'latency_info_unittest.cc',
diff --git a/ui/events/ipc/BUILD.gn b/ui/events/ipc/BUILD.gn
index 4adc3d264..f7eaf887 100644
--- a/ui/events/ipc/BUILD.gn
+++ b/ui/events/ipc/BUILD.gn
@@ -4,18 +4,18 @@
 
 import("//build/config/ui.gni")
 
-component("ipc") {
+component("events_ipc") {
   output_name = "events_ipc"
   sources = [
     "latency_info_param_traits.cc",
     "latency_info_param_traits.h",
   ]
 
-  defines = [ "EVENTS_IMPLEMENTATION" ]
+  defines = [ "EVENTS_IPC_IMPLEMENTATION" ]
 
   deps = [
     "//base",
     "//ipc",
-    "//ui/events",
+    "//ui/events:events_base",
   ]
 }
diff --git a/ui/events/ipc/events_ipc.gyp b/ui/events/ipc/events_ipc.gyp
deleted file mode 100644
index 898bf2fa..0000000
--- a/ui/events/ipc/events_ipc.gyp
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2014 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.
-
-{
-  'variables': {
-    'chromium_code': 1,
-  },
-  'targets': [
-    {
-      # GN version: //ui/events/ipc
-      'target_name': 'events_ipc',
-      'type': '<(component)',
-      'dependencies': [
-        '<(DEPTH)/base/base.gyp:base',
-        '<(DEPTH)/ipc/ipc.gyp:ipc',
-      ],
-      'defines': [
-        'EVENTS_IMPLEMENTATION',
-      ],
-      'include_dirs': [
-        '../..',
-      ],
-      'sources': [
-        'latency_info_param_traits.cc',
-        'latency_info_param_traits.h',
-      ],
-    },
-  ],
-}
diff --git a/ui/events/ipc/events_ipc_export.h b/ui/events/ipc/events_ipc_export.h
new file mode 100644
index 0000000..a02d669
--- /dev/null
+++ b/ui/events/ipc/events_ipc_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 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.
+
+#ifndef UI_EVENTS_EVENTS_IPC_EXPORT_H_
+#define UI_EVENTS_EVENTS_IPC_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(EVENTS_IPC_IMPLEMENTATION)
+#define EVENTS_IPC_EXPORT __declspec(dllexport)
+#else
+#define EVENTS_IPC_EXPORT __declspec(dllimport)
+#endif  // defined(EVENTS_IPC_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(EVENTS_IPC_IMPLEMENTATION)
+#define EVENTS_IPC_EXPORT __attribute__((visibility("default")))
+#else
+#define EVENTS_IPC_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define EVENTS_IPC_EXPORT
+#endif
+
+#endif  // UI_EVENTS_EVENTS_IPC_EXPORT_H_
diff --git a/ui/events/ipc/latency_info_param_traits.cc b/ui/events/ipc/latency_info_param_traits.cc
index 0b36c312..0fcce352 100644
--- a/ui/events/ipc/latency_info_param_traits.cc
+++ b/ui/events/ipc/latency_info_param_traits.cc
@@ -2,25 +2,85 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/events/ipc/latency_info_param_traits.h"
+#include "ui/events/ipc/latency_info_param_traits_macros.h"
 
 // Generate param traits write methods.
 #include "ipc/param_traits_write_macros.h"
 namespace IPC {
-#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
-#include "ui/events/ipc/latency_info_param_traits.h"
+#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#include "ui/events/ipc/latency_info_param_traits_macros.h"
 }  // namespace IPC
 
 // Generate param traits read methods.
 #include "ipc/param_traits_read_macros.h"
 namespace IPC {
-#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
-#include "ui/events/ipc/latency_info_param_traits.h"
+#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#include "ui/events/ipc/latency_info_param_traits_macros.h"
 }  // namespace IPC
 
 // Generate param traits log methods.
 #include "ipc/param_traits_log_macros.h"
 namespace IPC {
-#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
+#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#include "ui/events/ipc/latency_info_param_traits_macros.h"
+}  // namespace IPC
+
+// Implemetation for ParamTraits<ui::LatencyInfo>.
 #include "ui/events/ipc/latency_info_param_traits.h"
+
+namespace IPC {
+void ParamTraits<ui::LatencyInfo>::Write(Message* m,
+                                         const param_type& p) {
+  WriteParam(m, p.trace_name_);
+  WriteParam(m, p.latency_components_);
+  WriteParam(m, p.input_coordinates_size_);
+  for (size_t i = 0; i < p.input_coordinates_size_; i++) {
+    WriteParam(m, p.input_coordinates_[i]);
+  }
+  WriteParam(m, p.trace_id_);
+  WriteParam(m, p.terminated_);
+}
+
+bool ParamTraits<ui::LatencyInfo>::Read(const Message* m,
+                                        base::PickleIterator* iter,
+                                        param_type* p) {
+  if (!ReadParam(m, iter, &p->trace_name_))
+    return false;
+  if (!ReadParam(m, iter, &p->latency_components_))
+    return false;
+
+  ui::LatencyInfo::InputCoordinate input_coordinates;
+  uint32 input_coordinates_size;
+  if (!ReadParam(m, iter, &input_coordinates_size))
+    return false;
+  for (size_t i = 0; i < input_coordinates_size; i++) {
+    if (!ReadParam(m, iter, &input_coordinates))
+        return false;
+    p->AddInputCoordinate(input_coordinates);
+  }
+  if (!ReadParam(m, iter, &p->trace_id_))
+    return false;
+  if (!ReadParam(m, iter, &p->terminated_))
+    return false;
+
+  return true;
+}
+
+void ParamTraits<ui::LatencyInfo>::Log(const param_type& p,
+                                       std::string* l) {
+  LogParam(p.trace_name_, l);
+  l->append(" ");
+  LogParam(p.latency_components_, l);
+  l->append(" ");
+  LogParam(p.input_coordinates_size_, l);
+  l->append(" ");
+  for (size_t i = 0; i < p.input_coordinates_size_; i++) {
+    LogParam(p.input_coordinates_[i], l);
+    l->append(" ");
+  }
+  LogParam(p.trace_id_, l);
+  l->append(" ");
+  LogParam(p.terminated_, l);
+}
+
 }  // namespace IPC
diff --git a/ui/events/ipc/latency_info_param_traits.h b/ui/events/ipc/latency_info_param_traits.h
index e33a044..0716f43 100644
--- a/ui/events/ipc/latency_info_param_traits.h
+++ b/ui/events/ipc/latency_info_param_traits.h
@@ -5,35 +5,17 @@
 #ifndef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
 #define UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
 
-#include "ipc/ipc_message_macros.h"
-#include "ui/events/events_export.h"
+#include "ui/events/ipc/events_ipc_export.h"
 #include "ui/events/latency_info.h"
 
-#undef IPC_MESSAGE_EXPORT
-#define IPC_MESSAGE_EXPORT EVENTS_EXPORT
-
-IPC_ENUM_TRAITS_MAX_VALUE(ui::LatencyComponentType,
-                          ui::LATENCY_COMPONENT_TYPE_LAST)
-
-IPC_STRUCT_TRAITS_BEGIN(ui::LatencyInfo::LatencyComponent)
-  IPC_STRUCT_TRAITS_MEMBER(sequence_number)
-  IPC_STRUCT_TRAITS_MEMBER(event_time)
-  IPC_STRUCT_TRAITS_MEMBER(event_count)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(ui::LatencyInfo::InputCoordinate)
-IPC_STRUCT_TRAITS_MEMBER(x)
-IPC_STRUCT_TRAITS_MEMBER(y)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(ui::LatencyInfo)
-  IPC_STRUCT_TRAITS_MEMBER(latency_components)
-  IPC_STRUCT_TRAITS_MEMBER(trace_id)
-  IPC_STRUCT_TRAITS_MEMBER(terminated)
-  IPC_STRUCT_TRAITS_MEMBER(input_coordinates_size)
-  IPC_STRUCT_TRAITS_MEMBER(input_coordinates[0])
-  IPC_STRUCT_TRAITS_MEMBER(input_coordinates[1])
-  IPC_STRUCT_TRAITS_MEMBER(trace_name)
-IPC_STRUCT_TRAITS_END()
+namespace IPC {
+template <>
+struct EVENTS_IPC_EXPORT ParamTraits<ui::LatencyInfo> {
+  typedef ui::LatencyInfo param_type;
+  static void Write(Message* m, const param_type& p);
+  static bool Read(const Message* m, base::PickleIterator* iter, param_type* p);
+  static void Log(const param_type& p, std::string* l);
+};
+}  // namespace IPC
 
 #endif // UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
diff --git a/ui/events/ipc/latency_info_param_traits_macros.h b/ui/events/ipc/latency_info_param_traits_macros.h
new file mode 100644
index 0000000..40bf738
--- /dev/null
+++ b/ui/events/ipc/latency_info_param_traits_macros.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#define UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+
+#include "ipc/ipc_message_macros.h"
+#include "ui/events/ipc/events_ipc_export.h"
+#include "ui/events/latency_info.h"
+
+#undef IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_EXPORT EVENTS_IPC_EXPORT
+
+IPC_ENUM_TRAITS_MAX_VALUE(ui::LatencyComponentType,
+                          ui::LATENCY_COMPONENT_TYPE_LAST)
+
+IPC_STRUCT_TRAITS_BEGIN(ui::LatencyInfo::LatencyComponent)
+  IPC_STRUCT_TRAITS_MEMBER(sequence_number)
+  IPC_STRUCT_TRAITS_MEMBER(event_time)
+  IPC_STRUCT_TRAITS_MEMBER(event_count)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(ui::LatencyInfo::InputCoordinate)
+  IPC_STRUCT_TRAITS_MEMBER(x)
+  IPC_STRUCT_TRAITS_MEMBER(y)
+IPC_STRUCT_TRAITS_END()
+
+#endif // UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
diff --git a/ui/events/ipc/latency_info_param_traits_unittest.cc b/ui/events/ipc/latency_info_param_traits_unittest.cc
new file mode 100644
index 0000000..0fa3e974
--- /dev/null
+++ b/ui/events/ipc/latency_info_param_traits_unittest.cc
@@ -0,0 +1,78 @@
+// 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 "ipc/ipc_message_macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/ipc/latency_info_param_traits.h"
+#include "ui/events/ipc/latency_info_param_traits_macros.h"
+
+namespace ui {
+
+TEST(LatencyInfoParamTraitsTest, Basic) {
+  LatencyInfo latency;
+  ASSERT_FALSE(latency.terminated());
+  ASSERT_EQ(0u, latency.input_coordinates_size_);
+  latency.AddLatencyNumber(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 1234, 0);
+  latency.AddLatencyNumber(INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 1234, 100);
+  latency.AddLatencyNumber(INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT,
+                           1234, 0);
+  EXPECT_TRUE(latency.AddInputCoordinate(
+      LatencyInfo::InputCoordinate(100, 200)));
+  EXPECT_TRUE(latency.AddInputCoordinate(
+      LatencyInfo::InputCoordinate(101, 201)));
+  // Up to 2 InputCoordinate is allowed.
+  EXPECT_FALSE(latency.AddInputCoordinate(
+      LatencyInfo::InputCoordinate(102, 202)));
+  EXPECT_EQ(100, latency.trace_id());
+  EXPECT_TRUE(latency.terminated());
+  EXPECT_EQ(2u, latency.input_coordinates_size_);
+
+  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::WriteParam(&msg, latency);
+  base::PickleIterator iter(msg);
+  LatencyInfo output;
+  EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output));
+
+  EXPECT_EQ(latency.trace_id(), output.trace_id());
+  EXPECT_EQ(latency.terminated(), output.terminated());
+  EXPECT_EQ(latency.input_coordinates_size_, output.input_coordinates_size_);
+  for (size_t i = 0; i < latency.input_coordinates_size_; i++) {
+    EXPECT_EQ(latency.input_coordinates_[i].x,
+              output.input_coordinates_[i].x);
+    EXPECT_EQ(latency.input_coordinates_[i].y,
+              output.input_coordinates_[i].y);
+  }
+
+  EXPECT_TRUE(output.FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
+                                 1234,
+                                 nullptr));
+
+  LatencyInfo::LatencyComponent rwh_comp;
+  EXPECT_TRUE(output.FindLatency(INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+                                 1234,
+                                 &rwh_comp));
+  EXPECT_EQ(100, rwh_comp.sequence_number);
+  EXPECT_EQ(1u, rwh_comp.event_count);
+
+  EXPECT_TRUE(output.FindLatency(
+      INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 1234, nullptr));
+}
+
+TEST(LatencyInfoParamTraitsTest, InvalidData) {
+  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::WriteParam(&msg, std::string());
+  ui::LatencyInfo::LatencyMap components;
+  IPC::WriteParam(&msg, components);
+  // input_coordinates_size is 2 but only one InputCoordinate is written.
+  IPC::WriteParam(&msg, static_cast<uint32>(2));
+  IPC::WriteParam(&msg, ui::LatencyInfo::InputCoordinate());
+  IPC::WriteParam(&msg, static_cast<int64>(1234));
+  IPC::WriteParam(&msg, true);
+
+  base::PickleIterator iter(msg);
+  LatencyInfo output;
+  EXPECT_FALSE(IPC::ReadParam(&msg, &iter, &output));
+}
+
+}  // namespace ui
diff --git a/ui/events/latency_info.cc b/ui/events/latency_info.cc
index 8bc94e2..fac3199d 100644
--- a/ui/events/latency_info.cc
+++ b/ui/events/latency_info.cc
@@ -9,9 +9,7 @@
 
 #include "base/json/json_writer.h"
 #include "base/lazy_instance.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/stringprintf.h"
-#include "base/trace_event/trace_event.h"
 
 namespace {
 
@@ -111,35 +109,6 @@
     : value_(value) {
 }
 
-// Converts latencyinfo into format that can be dumped into trace buffer.
-scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsTraceableData(
-    const ui::LatencyInfo& latency) {
-  scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
-  for (ui::LatencyInfo::LatencyMap::const_iterator it =
-           latency.latency_components.begin();
-       it != latency.latency_components.end(); ++it) {
-    base::DictionaryValue* component_info = new base::DictionaryValue();
-    component_info->SetDouble("comp_id", static_cast<double>(it->first.second));
-    component_info->SetDouble(
-        "time", static_cast<double>(it->second.event_time.ToInternalValue()));
-    component_info->SetDouble("count", it->second.event_count);
-    component_info->SetDouble("sequence_number", it->second.sequence_number);
-    record_data->Set(GetComponentName(it->first.first), component_info);
-  }
-  record_data->SetDouble("trace_id", static_cast<double>(latency.trace_id));
-
-  scoped_ptr<base::ListValue> coordinates(new base::ListValue());
-  for (size_t i = 0; i < latency.input_coordinates_size; i++) {
-    scoped_ptr<base::DictionaryValue> coordinate_pair(
-        new base::DictionaryValue());
-    coordinate_pair->SetDouble("x", latency.input_coordinates[i].x);
-    coordinate_pair->SetDouble("y", latency.input_coordinates[i].y);
-    coordinates->Append(coordinate_pair.release());
-  }
-  record_data->Set("coordinates", coordinates.release());
-  return LatencyInfoTracedValue::FromValue(record_data.Pass());
-}
-
 struct BenchmarkEnabledInitializer {
   BenchmarkEnabledInitializer() :
       benchmark_enabled(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
@@ -163,7 +132,7 @@
 }
 
 LatencyInfo::LatencyInfo()
-    : input_coordinates_size(0), trace_id(-1), terminated(false) {
+    : input_coordinates_size_(0), trace_id_(-1), terminated_(false) {
 }
 
 LatencyInfo::~LatencyInfo() {
@@ -176,44 +145,32 @@
                << latency_info.size() << " is too big.";
     return false;
   }
-  for (size_t i = 0; i < latency_info.size(); i++) {
-    if (latency_info[i].input_coordinates_size > kMaxInputCoordinates) {
-      LOG(ERROR) << referring_msg << ", coordinate vector size "
-                 << latency_info[i].input_coordinates_size << " is too big.";
-      return false;
-    }
-  }
-
   return true;
 }
 
 void LatencyInfo::CopyLatencyFrom(const LatencyInfo& other,
                                   LatencyComponentType type) {
-  for (LatencyMap::const_iterator it = other.latency_components.begin();
-       it != other.latency_components.end();
-       ++it) {
-    if (it->first.first == type) {
-      AddLatencyNumberWithTimestamp(it->first.first,
-                                    it->first.second,
-                                    it->second.sequence_number,
-                                    it->second.event_time,
-                                    it->second.event_count);
+  for (const auto& lc : other.latency_components()) {
+    if (lc.first.first == type) {
+      AddLatencyNumberWithTimestamp(lc.first.first,
+                                    lc.first.second,
+                                    lc.second.sequence_number,
+                                    lc.second.event_time,
+                                    lc.second.event_count);
     }
   }
 }
 
 void LatencyInfo::AddNewLatencyFrom(const LatencyInfo& other) {
-    for (LatencyMap::const_iterator it = other.latency_components.begin();
-         it != other.latency_components.end();
-         ++it) {
-      if (!FindLatency(it->first.first, it->first.second, NULL)) {
-        AddLatencyNumberWithTimestamp(it->first.first,
-                                      it->first.second,
-                                      it->second.sequence_number,
-                                      it->second.event_time,
-                                      it->second.event_count);
-      }
+  for (const auto& lc : other.latency_components()) {
+    if (!FindLatency(lc.first.first, lc.first.second, NULL)) {
+      AddLatencyNumberWithTimestamp(lc.first.first,
+                                    lc.first.second,
+                                    lc.second.sequence_number,
+                                    lc.second.event_time,
+                                    lc.second.event_count);
     }
+  }
 }
 
 void LatencyInfo::AddLatencyNumber(LatencyComponentType component,
@@ -254,8 +211,8 @@
 
   if (IsBeginComponent(component)) {
     // Should only ever add begin component once.
-    CHECK_EQ(-1, trace_id);
-    trace_id = component_sequence_number;
+    CHECK_EQ(-1, trace_id_);
+    trace_id_ = component_sequence_number;
 
     if (*benchmark_enabled) {
       // The timestamp for ASYNC_BEGIN trace event is used for drawing the
@@ -286,28 +243,28 @@
 
       if (trace_name_str) {
         if (IsInputLatencyBeginComponent(component))
-          trace_name = std::string("InputLatency::") + trace_name_str;
+          trace_name_ = std::string("InputLatency::") + trace_name_str;
         else
-          trace_name = std::string("Latency::") + trace_name_str;
+          trace_name_ = std::string("Latency::") + trace_name_str;
       }
 
       TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(
           "benchmark,latencyInfo",
-          trace_name.c_str(),
-          TRACE_ID_DONT_MANGLE(trace_id),
+          trace_name_.c_str(),
+          TRACE_ID_DONT_MANGLE(trace_id_),
           ts);
     }
 
     TRACE_EVENT_FLOW_BEGIN1(
-        "input,benchmark", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(trace_id),
-        "trace_id", trace_id);
+        "input,benchmark", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(trace_id_),
+        "trace_id", trace_id_);
   }
 
   LatencyMap::key_type key = std::make_pair(component, id);
-  LatencyMap::iterator it = latency_components.find(key);
-  if (it == latency_components.end()) {
+  LatencyMap::iterator it = latency_components_.find(key);
+  if (it == latency_components_.end()) {
     LatencyComponent info = {component_sequence_number, time, event_count};
-    latency_components[key] = info;
+    latency_components_[key] = info;
   } else {
     it->second.sequence_number = std::max(component_sequence_number,
                                           it->second.sequence_number);
@@ -322,29 +279,58 @@
     }
   }
 
-  if (IsTerminalComponent(component) && trace_id != -1) {
+  if (IsTerminalComponent(component) && trace_id_ != -1) {
     // Should only ever add terminal component once.
-    CHECK(!terminated);
-    terminated = true;
+    CHECK(!terminated_);
+    terminated_ = true;
 
     if (*benchmark_enabled) {
       TRACE_EVENT_COPY_ASYNC_END1("benchmark,latencyInfo",
-                                  trace_name.c_str(),
-                                  TRACE_ID_DONT_MANGLE(trace_id),
-                                  "data", AsTraceableData(*this));
+                                  trace_name_.c_str(),
+                                  TRACE_ID_DONT_MANGLE(trace_id_),
+                                  "data", AsTraceableData());
     }
 
     TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0(
-        "input,benchmark", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(trace_id));
+        "input,benchmark", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(trace_id_));
   }
 }
 
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+LatencyInfo::AsTraceableData() {
+  scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
+  for (const auto& lc : latency_components_) {
+    scoped_ptr<base::DictionaryValue>
+        component_info(new base::DictionaryValue());
+    component_info->SetDouble("comp_id", static_cast<double>(lc.first.second));
+    component_info->SetDouble(
+        "time",
+        static_cast<double>(lc.second.event_time.ToInternalValue()));
+    component_info->SetDouble("count", lc.second.event_count);
+    component_info->SetDouble("sequence_number",
+                              lc.second.sequence_number);
+    record_data->Set(GetComponentName(lc.first.first), component_info.Pass());
+  }
+  record_data->SetDouble("trace_id", static_cast<double>(trace_id_));
+
+  scoped_ptr<base::ListValue> coordinates(new base::ListValue());
+  for (size_t i = 0; i < input_coordinates_size_; i++) {
+    scoped_ptr<base::DictionaryValue> coordinate_pair(
+        new base::DictionaryValue());
+    coordinate_pair->SetDouble("x", input_coordinates_[i].x);
+    coordinate_pair->SetDouble("y", input_coordinates_[i].y);
+    coordinates->Append(coordinate_pair.release());
+  }
+  record_data->Set("coordinates", coordinates.release());
+  return LatencyInfoTracedValue::FromValue(record_data.Pass());
+}
+
 bool LatencyInfo::FindLatency(LatencyComponentType type,
                               int64 id,
                               LatencyComponent* output) const {
-  LatencyMap::const_iterator it = latency_components.find(
+  LatencyMap::const_iterator it = latency_components_.find(
       std::make_pair(type, id));
-  if (it == latency_components.end())
+  if (it == latency_components_.end())
     return false;
   if (output)
     *output = it->second;
@@ -352,20 +338,23 @@
 }
 
 void LatencyInfo::RemoveLatency(LatencyComponentType type) {
-  LatencyMap::iterator it = latency_components.begin();
-  while (it != latency_components.end()) {
+  LatencyMap::iterator it = latency_components_.begin();
+  while (it != latency_components_.end()) {
     if (it->first.first == type) {
       LatencyMap::iterator tmp = it;
       ++it;
-      latency_components.erase(tmp);
+      latency_components_.erase(tmp);
     } else {
       it++;
     }
   }
 }
 
-void LatencyInfo::Clear() {
-  latency_components.clear();
+bool LatencyInfo::AddInputCoordinate(const InputCoordinate& input_coordinate) {
+  if (input_coordinates_size_ >= kMaxInputCoordinates)
+    return false;
+  input_coordinates_[input_coordinates_size_++] = input_coordinate;
+  return true;
 }
 
 }  // namespace ui
diff --git a/ui/events/latency_info.h b/ui/events/latency_info.h
index 4abcdc1..443e5fb9 100644
--- a/ui/events/latency_info.h
+++ b/ui/events/latency_info.h
@@ -11,7 +11,11 @@
 
 #include "base/basictypes.h"
 #include "base/containers/small_map.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "ipc/ipc_param_traits.h"
 #include "ui/events/events_base_export.h"
 
 namespace ui {
@@ -85,7 +89,8 @@
     INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT,
 };
 
-struct EVENTS_BASE_EXPORT LatencyInfo {
+class EVENTS_BASE_EXPORT LatencyInfo {
+ public:
   struct LatencyComponent {
     // Nondecreasing number that can be used to determine what events happened
     // in the component at the time this struct was sent on to the next
@@ -117,7 +122,6 @@
       kTypicalMaxComponentsPerLatencyInfo> LatencyMap;
 
   LatencyInfo();
-
   ~LatencyInfo();
 
   // Returns true if the vector |latency_info| is valid. Returns false
@@ -158,13 +162,6 @@
                                      base::TimeTicks time,
                                      uint32 event_count);
 
-  void AddLatencyNumberWithTimestampImpl(LatencyComponentType component,
-                                         int64 id,
-                                         int64 component_sequence_number,
-                                         base::TimeTicks time,
-                                         uint32 event_count,
-                                         const char* trace_name_str);
-
   // Returns true if the a component with |type| and |id| is found in
   // the latency_components and the component is stored to |output| if
   // |output| is not NULL. Returns false if no such component is found.
@@ -174,22 +171,47 @@
 
   void RemoveLatency(LatencyComponentType type);
 
-  void Clear();
+  // Returns true if there is still room for keeping the |input_coordinate|,
+  // false otherwise.
+  bool AddInputCoordinate(const InputCoordinate& input_coordinate);
+
+  uint32 input_coordinates_size() const { return input_coordinates_size_; }
+  const InputCoordinate* input_coordinates() const {
+    return input_coordinates_;
+  }
+  const LatencyMap& latency_components() const { return latency_components_; }
+
+  bool terminated() const { return terminated_; }
+  int64 trace_id() const { return trace_id_; }
+
+ private:
+  void AddLatencyNumberWithTimestampImpl(LatencyComponentType component,
+                                         int64 id,
+                                         int64 component_sequence_number,
+                                         base::TimeTicks time,
+                                         uint32 event_count,
+                                         const char* trace_name_str);
+
+  // Converts latencyinfo into format that can be dumped into trace buffer.
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsTraceableData();
 
   // Shown as part of the name of the trace event for this LatencyInfo.
   // String is empty if no tracing is enabled.
-  std::string trace_name;
+  std::string trace_name_;
 
-  LatencyMap latency_components;
+  LatencyMap latency_components_;
 
   // These coordinates represent window coordinates of the original input event.
-  uint32 input_coordinates_size;
-  InputCoordinate input_coordinates[kMaxInputCoordinates];
+  uint32 input_coordinates_size_;
+  InputCoordinate input_coordinates_[kMaxInputCoordinates];
 
   // The unique id for matching the ASYNC_BEGIN/END trace event.
-  int64 trace_id;
+  int64 trace_id_;
   // Whether a terminal component has been added.
-  bool terminated;
+  bool terminated_;
+
+  FRIEND_TEST_ALL_PREFIXES(LatencyInfoParamTraitsTest, Basic);
+  friend struct IPC::ParamTraits<ui::LatencyInfo>;
 };
 
 }  // namespace ui
diff --git a/ui/events/latency_info_unittest.cc b/ui/events/latency_info_unittest.cc
index 2f9ad05..26dcef2a 100644
--- a/ui/events/latency_info_unittest.cc
+++ b/ui/events/latency_info_unittest.cc
@@ -21,7 +21,7 @@
                                      base::TimeTicks::FromInternalValue(1000),
                                      2);
 
-  EXPECT_EQ(info.latency_components.size(), 2u);
+  EXPECT_EQ(info.latency_components().size(), 2u);
   LatencyInfo::LatencyComponent component;
   EXPECT_FALSE(
       info.FindLatency(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, &component));
@@ -52,7 +52,7 @@
                                      base::TimeTicks::FromInternalValue(200),
                                      3);
 
-  EXPECT_EQ(info.latency_components.size(), 1u);
+  EXPECT_EQ(info.latency_components().size(), 1u);
   LatencyInfo::LatencyComponent component;
   EXPECT_FALSE(
       info.FindLatency(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, &component));
@@ -65,17 +65,4 @@
   EXPECT_EQ(component.event_time.ToInternalValue(), (100 * 2 + 200 * 3) / 5);
 }
 
-TEST(LatencyInfoTest, ClearEvents) {
-  LatencyInfo info;
-  info.AddLatencyNumberWithTimestamp(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
-                                     0,
-                                     30,
-                                     base::TimeTicks::FromInternalValue(100),
-                                     2);
-
-  EXPECT_EQ(info.latency_components.size(), 1u);
-  info.Clear();
-  EXPECT_EQ(info.latency_components.size(), 0u);
-}
-
 }  // namespace ui