/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tools.perflib.vmtrace.viz;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.util.concurrent.TimeUnit;
public class TimeScaleRenderer {
/** Offset of the horizontal line indicating the timeline from the top of the screen. */
private static final int TIMELINE_Y_OFFSET = 20;
/** Horizontal padding from a marker to where its corresponding time is drawn. */
public static final int TIMELINE_UNIT_HORIZONTAL_PADDING = 5;
/** Vertical padding from the horizontal timeline to where the time units are drawn. */
public static final int TIMELINE_UNIT_VERTICAL_PADDING = 5;
private final long mStartTime;
private final TimeUnit mTimeUnits;
private double[] mPoints = new double[8];
private AffineTransform mViewTransform;
private AffineTransform mViewTransformInverse;
public TimeScaleRenderer(long startTime, TimeUnit unit) {
mStartTime = startTime;
mTimeUnits = unit;
}
public void paint(Graphics2D g2d, AffineTransform viewPortTransform, int screenWidth) {
AffineTransform originalTransform = g2d.getTransform();
// draw the custom timeline for the current viewport transformation
drawTimeLine(g2d, viewPortTransform, screenWidth);
g2d.setTransform(originalTransform);
}
private void drawTimeLine(Graphics2D g2d, AffineTransform viewPortTransform, int screenWidth) {
createInverse(viewPortTransform);
// (0,y)
mPoints[0] = 0;
mPoints[1] = 0; // Note: We don't care about the y-coordinate here.
// (screenWidth, y)
mPoints[2] = screenWidth;
mPoints[3] = 0; // Note: We don't care about the y-coordinate here.
// The timeline goes from (0,y) to (screenWidth,y) in screen space. We apply the
// inverse of the view transform to convert these to item space.
mViewTransformInverse.transform(mPoints, 0, mPoints, 4, 2);
// Offset both the left and right end points by the start time.
long start = (long) mPoints[4] + mStartTime;
long end = (long) mPoints[6] + mStartTime;
g2d.setColor(Color.BLACK);
// draw the horizontal timeline
g2d.drawLine(0, TIMELINE_Y_OFFSET, screenWidth, TIMELINE_Y_OFFSET);
// draw the time at the leftmost end of the screen corresponding to (0,y)
String time = TimeUtils.makeHumanReadable(start, end - start, mTimeUnits);
g2d.drawString(time,
0 + TIMELINE_UNIT_HORIZONTAL_PADDING,
TIMELINE_Y_OFFSET - TIMELINE_UNIT_VERTICAL_PADDING);
// draw the time at the leftmost end of the screen corresponding to (screen width,y)
time = TimeUtils.makeHumanReadable(end, end - start, mTimeUnits);
g2d.drawString(time,
screenWidth - g2d.getFontMetrics().stringWidth(time)
- TIMELINE_UNIT_HORIZONTAL_PADDING,
TIMELINE_Y_OFFSET - TIMELINE_UNIT_VERTICAL_PADDING);
}
public int getLayoutHeight() {
return TIMELINE_Y_OFFSET + 10;
}
private void createInverse(AffineTransform viewPortTransform) {
if (!viewPortTransform.equals(mViewTransform)) {
// cache source transformation matrix
mViewTransform = new AffineTransform(viewPortTransform);
try {
mViewTransformInverse = mViewTransform.createInverse();
} catch (NoninvertibleTransformException e) {
// This scenario should never occur since the viewport is only zoomed or panned,
// both of which are invertible.
mViewTransformInverse = new AffineTransform();
}
}
}
}