• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2018 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {assertTrue} from '../base/logging';
16import {
17  HighPrecisionTime,
18  HighPrecisionTimeSpan,
19} from '../common/high_precision_time';
20import {Span} from '../common/time';
21import {
22  TPDuration,
23  TPTime,
24} from '../common/time';
25
26export class TimeScale {
27  private _start: HighPrecisionTime;
28  private _durationNanos: number;
29  readonly pxSpan: PxSpan;
30  private _nanosPerPx = 0;
31  private _startSec: number;
32
33  constructor(start: HighPrecisionTime, durationNanos: number, pxSpan: PxSpan) {
34    // TODO(stevegolton): Ensure duration & pxSpan > 0.
35    // assertTrue(pxSpan.start < pxSpan.end, 'Px start >= end');
36    // assertTrue(durationNanos < 0, 'Duration <= 0');
37    this.pxSpan = pxSpan;
38    this._start = start;
39    this._durationNanos = durationNanos;
40    if (durationNanos <= 0 || pxSpan.delta <= 0) {
41      this._nanosPerPx = 1;
42    } else {
43      this._nanosPerPx = durationNanos / (pxSpan.delta);
44    }
45    this._startSec = this._start.seconds;
46  }
47
48  get timeSpan(): Span<HighPrecisionTime> {
49    const end = this._start.addNanos(this._durationNanos);
50    return new HighPrecisionTimeSpan(this._start, end);
51  }
52
53  tpTimeToPx(ts: TPTime): number {
54    // WARNING: Number(bigint) can be surprisingly slow. Avoid in hotpath.
55    const timeOffsetNanos = Number(ts - this._start.base) - this._start.offset;
56    return this.pxSpan.start + timeOffsetNanos / this._nanosPerPx;
57  }
58
59  secondsToPx(seconds: number): number {
60    const timeOffset = (seconds - this._startSec) * 1e9;
61    return this.pxSpan.start + timeOffset / this._nanosPerPx;
62  }
63
64  hpTimeToPx(time: HighPrecisionTime): number {
65    const timeOffsetNanos = time.subtract(this._start).nanos;
66    return this.pxSpan.start + timeOffsetNanos / this._nanosPerPx;
67  }
68
69  // Convert pixels to a high precision time object, which can be futher
70  // converted to other time formats.
71  pxToHpTime(px: number): HighPrecisionTime {
72    const offsetNanos = (px - this.pxSpan.start) * this._nanosPerPx;
73    return this._start.addNanos(offsetNanos);
74  }
75
76  durationToPx(dur: TPDuration): number {
77    // WARNING: Number(bigint) can be surprisingly slow. Avoid in hotpath.
78    return Number(dur) / this._nanosPerPx;
79  }
80
81  pxDeltaToDuration(pxDelta: number): HighPrecisionTime {
82    const time = pxDelta * this._nanosPerPx;
83    return HighPrecisionTime.fromNanos(time);
84  }
85}
86
87export class PxSpan {
88  constructor(private _start: number, private _end: number) {
89    assertTrue(_start <= _end, 'PxSpan start > end');
90  }
91
92  get start(): number {
93    return this._start;
94  }
95
96  get end(): number {
97    return this._end;
98  }
99
100  get delta(): number {
101    return this._end - this._start;
102  }
103}
104