summaryrefslogtreecommitdiff
path: root/chromium/content/common/inter_process_time_ticks_converter.h
blob: 01c6124288db3499d6ce6c0df9a261e50c771beb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright (c) 2011 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 CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_
#define CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_

#include "base/time/time.h"
#include "content/common/content_export.h"

namespace content {

class LocalTimeDelta;
class LocalTimeTicks;
class RemoteTimeDelta;
class RemoteTimeTicks;

// On Windows, TimeTicks are not consistent between processes. Often, the values
// on one process have a static offset relative to another. Occasionally, these
// offsets shift while running.
//
// To combat this, any TimeTicks values sent from the remote process to the
// local process must be tweaked in order to appear monotonic.
//
// In order to properly tweak ticks, we need 4 reference points:
//
// - |local_lower_bound|:  A known point, recorded on the local process, that
//                         occurs before any remote values that will be
//                         converted.
// - |remote_lower_bound|: The equivalent point on the remote process. This
//                         should be recorded immediately after
//                         |local_lower_bound|.
// - |local_upper_bound|:  A known point, recorded on the local process, that
//                         occurs after any remote values that will be
//                         converted.
// - |remote_upper_bound|: The equivalent point on the remote process. This
//                         should be recorded immediately before
//                         |local_upper_bound|.
//
// Once these bounds are determined, values within the remote process's range
// can be converted to the local process's range. The values are converted as
// follows:
//
// 1. If the remote's range exceeds the local's range, it is scaled to fit.
//    Any values converted will have the same scale factor applied.
//
// 2. The remote's range is shifted so that it is centered within the
//    local's range. Any values converted will be shifted the same amount.
class CONTENT_EXPORT InterProcessTimeTicksConverter {
 public:
  InterProcessTimeTicksConverter(const LocalTimeTicks& local_lower_bound,
                                 const LocalTimeTicks& local_upper_bound,
                                 const RemoteTimeTicks& remote_lower_bound,
                                 const RemoteTimeTicks& remote_upper_bound);

  // Returns the value within the local's bounds that correlates to
  // |remote_ms|.
  LocalTimeTicks ToLocalTimeTicks(const RemoteTimeTicks& remote_ms) const;

  // Returns the equivalent delta after applying remote-to-local scaling to
  // |remote_delta|.
  LocalTimeDelta ToLocalTimeDelta(const RemoteTimeDelta& remote_delta) const;

 private:
  int64 Convert(int64 value) const;

  // The local time which |remote_lower_bound_| is mapped to.
  int64 local_base_time_;

  int64 numerator_;
  int64 denominator_;

  int64 remote_lower_bound_;
  int64 remote_upper_bound_;
};

class CONTENT_EXPORT LocalTimeDelta {
 public:
  int ToInt32() const { return value_; }

 private:
  friend class InterProcessTimeTicksConverter;
  friend class LocalTimeTicks;

  LocalTimeDelta(int value) : value_(value) {}

  int value_;
};

class CONTENT_EXPORT LocalTimeTicks {
 public:
  static LocalTimeTicks FromTimeTicks(const base::TimeTicks& value) {
    return LocalTimeTicks(value.ToInternalValue());
  }

  base::TimeTicks ToTimeTicks() {
    return base::TimeTicks::FromInternalValue(value_);
  }

  LocalTimeTicks operator+(const LocalTimeDelta& delta) {
    return LocalTimeTicks(value_ + delta.value_);
  }

 private:
  friend class InterProcessTimeTicksConverter;

  LocalTimeTicks(int64 value) : value_(value) {}

  int64 value_;
};

class CONTENT_EXPORT RemoteTimeDelta {
 public:
  static RemoteTimeDelta FromRawDelta(int delta) {
    return RemoteTimeDelta(delta);
  }

 private:
  friend class InterProcessTimeTicksConverter;
  friend class RemoteTimeTicks;

  RemoteTimeDelta(int value) : value_(value) {}

  int value_;
};

class CONTENT_EXPORT RemoteTimeTicks {
 public:
  static RemoteTimeTicks FromTimeTicks(const base::TimeTicks& ticks) {
    return RemoteTimeTicks(ticks.ToInternalValue());
  }

  RemoteTimeDelta operator-(const RemoteTimeTicks& rhs) const {
    return RemoteTimeDelta(value_ - rhs.value_);
  }

 private:
  friend class InterProcessTimeTicksConverter;

  RemoteTimeTicks(int64 value) : value_(value) {}

  int64 value_;
};

}  // namespace content

#endif  // CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_