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 {duration, Span, time} from '../base/time'; 17import { 18 HighPrecisionTime, 19 HighPrecisionTimeSpan, 20} from '../common/high_precision_time'; 21 22export class TimeScale { 23 private _start: HighPrecisionTime; 24 private _durationNanos: number; 25 readonly pxSpan: PxSpan; 26 private _nanosPerPx = 0; 27 28 static fromHPTimeSpan(span: Span<HighPrecisionTime>, pxSpan: PxSpan) { 29 return new TimeScale(span.start, span.duration.nanos, pxSpan); 30 } 31 32 constructor(start: HighPrecisionTime, durationNanos: number, pxSpan: PxSpan) { 33 this.pxSpan = pxSpan; 34 this._start = start; 35 this._durationNanos = durationNanos; 36 if (durationNanos <= 0 || pxSpan.delta <= 0) { 37 this._nanosPerPx = 1; 38 } else { 39 this._nanosPerPx = durationNanos / pxSpan.delta; 40 } 41 } 42 43 get timeSpan(): Span<HighPrecisionTime> { 44 const end = this._start.addNanos(this._durationNanos); 45 return new HighPrecisionTimeSpan(this._start, end); 46 } 47 48 timeToPx(ts: time): number { 49 // WARNING: Number(bigint) can be surprisingly slow. Avoid in hotpath. 50 const timeOffsetNanos = Number(ts - this._start.base) - this._start.offset; 51 return this.pxSpan.start + timeOffsetNanos / this._nanosPerPx; 52 } 53 54 hpTimeToPx(time: HighPrecisionTime): number { 55 const timeOffsetNanos = time.sub(this._start).nanos; 56 return this.pxSpan.start + timeOffsetNanos / this._nanosPerPx; 57 } 58 59 // Convert pixels to a high precision time object, which can be futher 60 // converted to other time formats. 61 pxToHpTime(px: number): HighPrecisionTime { 62 const offsetNanos = (px - this.pxSpan.start) * this._nanosPerPx; 63 return this._start.addNanos(offsetNanos); 64 } 65 66 durationToPx(dur: duration): number { 67 // WARNING: Number(bigint) can be surprisingly slow. Avoid in hotpath. 68 return Number(dur) / this._nanosPerPx; 69 } 70 71 pxDeltaToDuration(pxDelta: number): HighPrecisionTime { 72 const time = pxDelta * this._nanosPerPx; 73 return HighPrecisionTime.fromNanos(time); 74 } 75} 76 77export class PxSpan { 78 static readonly ZERO = new PxSpan(0, 0); 79 80 constructor(private _start: number, private _end: number) { 81 assertTrue(_start <= _end, 'PxSpan start > end'); 82 } 83 84 get start(): number { 85 return this._start; 86 } 87 88 get end(): number { 89 return this._end; 90 } 91 92 get delta(): number { 93 return this._end - this._start; 94 } 95} 96