QmlProfiler: Prevent integer overflows in timelinerenderer

When zooming in the x offset and width of events can be larger than 2^31.
We can restrict them to the visible area, though.

Task-number: QTCREATORBUG-11879
Change-Id: I841300b55cdd583d5c3fa58b196101038f6f6036
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
Ulf Hermann
2014-03-28 15:58:27 +01:00
parent 7238d1e0fb
commit ca78bb358b
2 changed files with 35 additions and 24 deletions

View File

@@ -44,7 +44,7 @@ using namespace QmlProfiler::Internal;
const int DefaultRowHeight = 30; const int DefaultRowHeight = 30;
TimelineRenderer::TimelineRenderer(QQuickPaintedItem *parent) : TimelineRenderer::TimelineRenderer(QQuickPaintedItem *parent) :
QQuickPaintedItem(parent), m_startTime(0), m_endTime(0), m_spacing(0), QQuickPaintedItem(parent), m_startTime(0), m_endTime(0), m_spacing(0), m_spacedDuration(0),
m_lastStartTime(0), m_lastEndTime(0) m_lastStartTime(0), m_lastEndTime(0)
, m_profilerModelProxy(0) , m_profilerModelProxy(0)
{ {
@@ -82,6 +82,20 @@ void TimelineRenderer::requestPaint()
update(); update();
} }
inline void TimelineRenderer::getItemXExtent(int modelIndex, int i, int &currentX, int &itemWidth)
{
qint64 start = m_profilerModelProxy->getStartTime(modelIndex, i) - m_startTime;
if (start > 0) {
currentX = start * m_spacing;
itemWidth = qMax(1.0, (qMin(m_profilerModelProxy->getDuration(modelIndex, i) *
m_spacing, m_spacedDuration)));
} else {
currentX = -OutOfScreenMargin;
itemWidth = qMax(1.0, (qMin((m_profilerModelProxy->getDuration(modelIndex, i) + start) *
m_spacing + OutOfScreenMargin, m_spacedDuration)));
}
}
void TimelineRenderer::paint(QPainter *p) void TimelineRenderer::paint(QPainter *p)
{ {
qint64 windowDuration = m_endTime - m_startTime; qint64 windowDuration = m_endTime - m_startTime;
@@ -89,6 +103,7 @@ void TimelineRenderer::paint(QPainter *p)
return; return;
m_spacing = qreal(width()) / windowDuration; m_spacing = qreal(width()) / windowDuration;
m_spacedDuration = (m_endTime - m_startTime) * m_spacing + 2 * OutOfScreenMargin;
p->setPen(Qt::transparent); p->setPen(Qt::transparent);
@@ -119,22 +134,19 @@ void TimelineRenderer::drawItemsToPainter(QPainter *p, int modelIndex, int fromI
for (int i = fromIndex; i <= toIndex; i++) { for (int i = fromIndex; i <= toIndex; i++) {
int currentX, currentY, itemWidth, itemHeight; int currentX, currentY, itemWidth, itemHeight;
currentX = (m_profilerModelProxy->getStartTime(modelIndex, i) - m_startTime) * m_spacing;
int rowNumber = m_profilerModelProxy->getEventRow(modelIndex, i); int rowNumber = m_profilerModelProxy->getEventRow(modelIndex, i);
currentY = (modelRowStart + rowNumber) * DefaultRowHeight - y(); currentY = (modelRowStart + rowNumber) * DefaultRowHeight - y();
if (currentY >= height()) if (currentY >= height())
continue; continue;
itemWidth = m_profilerModelProxy->getDuration(modelIndex, i) * m_spacing;
if (itemWidth < 1)
itemWidth = 1;
itemHeight = DefaultRowHeight * m_profilerModelProxy->getHeight(modelIndex, i); itemHeight = DefaultRowHeight * m_profilerModelProxy->getHeight(modelIndex, i);
currentY += DefaultRowHeight - itemHeight; currentY += DefaultRowHeight - itemHeight;
if (currentY + itemHeight < 0) if (currentY + itemHeight < 0)
continue; continue;
getItemXExtent(modelIndex, i, currentX, itemWidth);
// normal events // normal events
p->setBrush(m_profilerModelProxy->getColor(modelIndex, i)); p->setBrush(m_profilerModelProxy->getColor(modelIndex, i));
p->drawRect(currentX, currentY, itemWidth, itemHeight); p->drawRect(currentX, currentY, itemWidth, itemHeight);
@@ -171,14 +183,11 @@ void TimelineRenderer::drawSelectionBoxes(QPainter *p, int modelIndex, int fromI
if (m_profilerModelProxy->getEventId(modelIndex, i) != id) if (m_profilerModelProxy->getEventId(modelIndex, i) != id)
continue; continue;
currentX = (m_profilerModelProxy->getStartTime(modelIndex, i) - m_startTime) * m_spacing;
currentY = (modelRowStart + m_profilerModelProxy->getEventRow(modelIndex, i)) * DefaultRowHeight - y(); currentY = (modelRowStart + m_profilerModelProxy->getEventRow(modelIndex, i)) * DefaultRowHeight - y();
if (currentY + DefaultRowHeight < 0 || height() < currentY) if (currentY + DefaultRowHeight < 0 || height() < currentY)
continue; continue;
itemWidth = m_profilerModelProxy->getDuration(modelIndex, i) * m_spacing; getItemXExtent(modelIndex, i, currentX, itemWidth);
if (itemWidth < 1)
itemWidth = 1;
if (i == m_selectedItem) if (i == m_selectedItem)
selectedItemRect = QRect(currentX, currentY - 1, itemWidth, DefaultRowHeight + 1); selectedItemRect = QRect(currentX, currentY - 1, itemWidth, DefaultRowHeight + 1);
@@ -198,7 +207,7 @@ void TimelineRenderer::drawSelectionBoxes(QPainter *p, int modelIndex, int fromI
void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int modelIndex, int fromIndex, int toIndex) void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int modelIndex, int fromIndex, int toIndex)
{ {
int destindex; int destindex;
int xfrom, xto; int xfrom, xto, width;
int yfrom, yto; int yfrom, yto;
int radius = DefaultRowHeight / 3; int radius = DefaultRowHeight / 3;
QPen shadowPen = QPen(QColor("grey"),2); QPen shadowPen = QPen(QColor("grey"),2);
@@ -210,23 +219,20 @@ void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int modelIndex, int f
for (int i = fromIndex; i <= toIndex; i++) { for (int i = fromIndex; i <= toIndex; i++) {
destindex = m_profilerModelProxy->getBindingLoopDest(modelIndex, i); destindex = m_profilerModelProxy->getBindingLoopDest(modelIndex, i);
if (destindex >= 0) { if (destindex >= 0) {
// from
xfrom = (m_profilerModelProxy->getStartTime(modelIndex, i) +
m_profilerModelProxy->getDuration(modelIndex, i)/2 -
m_startTime) * m_spacing;
yfrom = getYPosition(modelIndex, i) + DefaultRowHeight / 2 - y();
// to // to
xto = (m_profilerModelProxy->getStartTime(modelIndex, destindex) + getItemXExtent(modelIndex, destindex, xto, width);
m_profilerModelProxy->getDuration(modelIndex, destindex)/2 - xto += width / 2;
m_startTime) * m_spacing;
yto = getYPosition(modelIndex, destindex) + DefaultRowHeight / 2 - y(); yto = getYPosition(modelIndex, destindex) + DefaultRowHeight / 2 - y();
// radius // from
int eventWidth = m_profilerModelProxy->getDuration(modelIndex, i) * m_spacing; getItemXExtent(modelIndex, i, xfrom, width);
xfrom += width / 2;
yfrom = getYPosition(modelIndex, i) + DefaultRowHeight / 2 - y();
// radius (derived from width of origin event)
radius = 5; radius = 5;
if (radius * 2 > eventWidth) if (radius * 2 > width)
radius = eventWidth / 2; radius = width / 2;
if (radius < 2) if (radius < 2)
radius = 2; radius = 2;

View File

@@ -195,9 +195,14 @@ private:
} }
private: private:
static const int OutOfScreenMargin = 3; // margin to make sure the rectangles stay invisible
inline void getItemXExtent(int modelIndex, int i, int &currentX, int &itemWidth);
qint64 m_startTime; qint64 m_startTime;
qint64 m_endTime; qint64 m_endTime;
qreal m_spacing; qreal m_spacing;
qreal m_spacedDuration;
qint64 m_lastStartTime; qint64 m_lastStartTime;
qint64 m_lastEndTime; qint64 m_lastEndTime;