From 1e4c29e111d4c5a2344f7370c399625c565ba72c 2013-08-26 09:07:10 From: Titta Heikkala Date: 2013-08-26 09:07:10 Subject: [PATCH] Fix zooming in crash The bounding rect has to fit inside int limits when zooming in, meaning that the height and width both have to be within the int limits (INT_MAX). QWidget::update() uses a region (based on bounding rect) that has to be compatible with QRect. The geometry change is only done if the bounding rect fulfills this requirement. Task-number: QTRD-1907 Change-Id: I4e874de355390c5fc983ac1e0976bf0d21e2d10c Reviewed-by: Miikka Heikkinen --- diff --git a/src/areachart/areachartitem.cpp b/src/areachart/areachartitem.cpp index 8b04084..adb540d 100644 --- a/src/areachart/areachartitem.cpp +++ b/src/areachart/areachartitem.cpp @@ -110,10 +110,16 @@ void AreaChartItem::updatePath() } } path.closeSubpath(); - prepareGeometryChange(); - m_path = path; - m_rect = path.boundingRect(); - update(); + + // Only zoom in if the bounding rect of the path fits inside int limits. QWidget::update() uses + // a region that has to be compatible with QRect. + if (path.boundingRect().height() <= INT_MAX + && path.boundingRect().width() <= INT_MAX) { + prepareGeometryChange(); + m_path = path; + m_rect = path.boundingRect(); + update(); + } } void AreaChartItem::handleUpdated() diff --git a/src/linechart/linechartitem.cpp b/src/linechart/linechartitem.cpp index 0c517df..1355867 100644 --- a/src/linechart/linechartitem.cpp +++ b/src/linechart/linechartitem.cpp @@ -276,13 +276,26 @@ void LineChartItem::updateGeometry() stroker.setCapStyle(Qt::SquareCap); stroker.setMiterLimit(m_linePen.miterLimit()); - prepareGeometryChange(); + QPainterPath checkShapePath = stroker.createStroke(fullPath); + + // Only zoom in if the bounding rects of the paths fit inside int limits. QWidget::update() uses + // a region that has to be compatible with QRect. + if (checkShapePath.boundingRect().height() <= INT_MAX + && checkShapePath.boundingRect().width() <= INT_MAX + && linePath.boundingRect().height() <= INT_MAX + && linePath.boundingRect().width() <= INT_MAX + && fullPath.boundingRect().height() <= INT_MAX + && fullPath.boundingRect().width() <= INT_MAX) { + prepareGeometryChange(); - m_linePath = linePath; - m_fullPath = fullPath; - m_shapePath = stroker.createStroke(fullPath); + m_linePath = linePath; + m_fullPath = fullPath; + m_shapePath = checkShapePath; - m_rect = m_shapePath.boundingRect(); + m_rect = m_shapePath.boundingRect(); + } else { + update(); + } } void LineChartItem::handleUpdated() diff --git a/src/scatterchart/scatterchartitem.cpp b/src/scatterchart/scatterchartitem.cpp index 200eda8..89a991e 100644 --- a/src/scatterchart/scatterchartitem.cpp +++ b/src/scatterchart/scatterchartitem.cpp @@ -126,31 +126,36 @@ void ScatterChartItem::updateGeometry() QRectF clipRect(QPointF(0,0),domain()->size()); - QVector offGridStatus = offGridStatusVector(); - const int seriesLastIndex = m_series->count() - 1; - - for (int i = 0; i < points.size(); i++) { - QGraphicsItem *item = items.at(i); - const QPointF &point = points.at(i); - const QRectF &rect = item->boundingRect(); - // During remove animation series may have different number of points, - // so ensure we don't go over the index. Animation handling itself ensures that - // if there is actually no points in the series, then it won't generate a fake point, - // so we can be assured there is always at least one point in m_series here. - // Note that marker map values can be technically incorrect during the animation, - // if it was caused by an insert, but this shouldn't be a problem as the points are - // fake anyway. After remove animation stops, geometry is updated to correct one. - m_markerMap[item] = m_series->at(qMin(seriesLastIndex, i)); - item->setPos(point.x() - rect.width() / 2, point.y() - rect.height() / 2); - - if (!m_visible || offGridStatus.at(i)) - item->setVisible(false); - else - item->setVisible(true); - } + // Only zoom in if the clipRect fits inside int limits. QWidget::update() uses + // a region that has to be compatible with QRect. + if (clipRect.height() <= INT_MAX + && clipRect.width() <= INT_MAX) { + QVector offGridStatus = offGridStatusVector(); + const int seriesLastIndex = m_series->count() - 1; + + for (int i = 0; i < points.size(); i++) { + QGraphicsItem *item = items.at(i); + const QPointF &point = points.at(i); + const QRectF &rect = item->boundingRect(); + // During remove animation series may have different number of points, + // so ensure we don't go over the index. Animation handling itself ensures that + // if there is actually no points in the series, then it won't generate a fake point, + // so we can be assured there is always at least one point in m_series here. + // Note that marker map values can be technically incorrect during the animation, + // if it was caused by an insert, but this shouldn't be a problem as the points are + // fake anyway. After remove animation stops, geometry is updated to correct one. + m_markerMap[item] = m_series->at(qMin(seriesLastIndex, i)); + item->setPos(point.x() - rect.width() / 2, point.y() - rect.height() / 2); + + if (!m_visible || offGridStatus.at(i)) + item->setVisible(false); + else + item->setVisible(true); + } - prepareGeometryChange(); - m_rect = clipRect; + prepareGeometryChange(); + m_rect = clipRect; + } } void ScatterChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) diff --git a/src/splinechart/splinechartitem.cpp b/src/splinechart/splinechartitem.cpp index 11f9ac9..fc42f52 100644 --- a/src/splinechart/splinechartitem.cpp +++ b/src/splinechart/splinechartitem.cpp @@ -267,7 +267,6 @@ void SplineChartItem::updateGeometry() } fullPath = splinePath; } - m_path = splinePath; QPainterPathStroker stroker; // The full path is comprised of three separate paths. @@ -278,10 +277,20 @@ void SplineChartItem::updateGeometry() stroker.setCapStyle(Qt::SquareCap); stroker.setMiterLimit(m_linePen.miterLimit()); - prepareGeometryChange(); + // Only zoom in if the bounding rects of the path fit inside int limits. QWidget::update() uses + // a region that has to be compatible with QRect. + QPainterPath checkShapePath = stroker.createStroke(fullPath); + if (checkShapePath.boundingRect().height() <= INT_MAX + && checkShapePath.boundingRect().width() <= INT_MAX + && splinePath.boundingRect().height() <= INT_MAX + && splinePath.boundingRect().width() <= INT_MAX) { + m_path = splinePath; - m_fullPath = stroker.createStroke(fullPath); - m_rect = m_fullPath.boundingRect(); + prepareGeometryChange(); + + m_fullPath = checkShapePath; + m_rect = m_fullPath.boundingRect(); + } } /*!