1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/common/inter_process_time_ticks_converter.h"
6 
7 #include <algorithm>
8 
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 
12 namespace content {
13 
InterProcessTimeTicksConverter(LocalTimeTicks local_lower_bound,LocalTimeTicks local_upper_bound,RemoteTimeTicks remote_lower_bound,RemoteTimeTicks remote_upper_bound)14 InterProcessTimeTicksConverter::InterProcessTimeTicksConverter(
15     LocalTimeTicks local_lower_bound,
16     LocalTimeTicks local_upper_bound,
17     RemoteTimeTicks remote_lower_bound,
18     RemoteTimeTicks remote_upper_bound)
19     : local_range_(local_upper_bound - local_lower_bound),
20       remote_lower_bound_(remote_lower_bound),
21       remote_upper_bound_(remote_upper_bound) {
22   RemoteTimeDelta remote_range = remote_upper_bound - remote_lower_bound;
23 
24   DCHECK_LE(LocalTimeDelta(), local_range_);
25   DCHECK_LE(RemoteTimeDelta(), remote_range);
26 
27   if (remote_range.ToTimeDelta() <= local_range_.ToTimeDelta()) {
28     // We fit!  Center the source range on the target range.
29     range_conversion_rate_ = 1.0;
30     base::TimeDelta diff =
31         local_range_.ToTimeDelta() - remote_range.ToTimeDelta();
32 
33     local_base_time_ =
34         local_lower_bound + LocalTimeDelta::FromTimeDelta(diff / 2);
35     // When converting times, remote bounds should fall within local bounds.
36     DCHECK_LE(local_lower_bound, ToLocalTimeTicks(remote_lower_bound));
37     DCHECK_LE(ToLocalTimeTicks(remote_upper_bound), local_upper_bound);
38     return;
39   }
40 
41   // Interpolate values so that remote range will be will exactly fit into the
42   // local range, if possible.
43   DCHECK_GT(remote_range.ToTimeDelta().InMicroseconds(), 0);
44   range_conversion_rate_ =
45       static_cast<double>(local_range_.ToTimeDelta().InMicroseconds()) /
46       remote_range.ToTimeDelta().InMicroseconds();
47   local_base_time_ = local_lower_bound;
48 }
49 
ToLocalTimeTicks(RemoteTimeTicks remote_time_ticks) const50 LocalTimeTicks InterProcessTimeTicksConverter::ToLocalTimeTicks(
51     RemoteTimeTicks remote_time_ticks) const {
52   // If input time is "null", return another "null" time.
53   if (remote_time_ticks.is_null())
54     return LocalTimeTicks();
55 
56   RemoteTimeDelta remote_delta = remote_time_ticks - remote_lower_bound_;
57 
58   DCHECK_LE(remote_time_ticks, remote_upper_bound_);
59   return local_base_time_ + ToLocalTimeDelta(remote_delta);
60 }
61 
ToLocalTimeDelta(RemoteTimeDelta remote_delta) const62 LocalTimeDelta InterProcessTimeTicksConverter::ToLocalTimeDelta(
63     RemoteTimeDelta remote_delta) const {
64   DCHECK_LE(remote_lower_bound_ + remote_delta, remote_upper_bound_);
65 
66   // For remote times that come before remote time range, apply just time
67   // offset and ignore scaling, so as to avoid extrapolation error for values
68   // long in the past.
69   if (remote_delta <= RemoteTimeDelta())
70     return LocalTimeDelta::FromTimeDelta(remote_delta.ToTimeDelta());
71 
72   return std::min(local_range_,
73                   LocalTimeDelta::FromTimeDelta(remote_delta.ToTimeDelta() *
74                                                 range_conversion_rate_));
75 }
76 
GetSkewForMetrics() const77 base::TimeDelta InterProcessTimeTicksConverter::GetSkewForMetrics() const {
78   return remote_lower_bound_.ToTimeTicks() - local_base_time_.ToTimeTicks();
79 }
80 
81 }  // namespace content
82