text: // 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.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_
  