summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBjoern Erik Nilsen <bjorn.nilsen@nokia.com>2009-05-08 14:00:57 (GMT)
committerBjørn Erik Nilsen <bjorn.nilsen@nokia.com>2009-05-15 15:55:44 (GMT)
commit59cc08796bfb88bc0010006f365f1361462761aa (patch)
tree44eebedc40e44546a5788cfb3ac497f1bab7e7d6 /src
parentb0095f7f8925cf571224d348124f08c56f7f46e9 (diff)
downloadQt-59cc08796bfb88bc0010006f365f1361462761aa.zip
Qt-59cc08796bfb88bc0010006f365f1361462761aa.tar.gz
Qt-59cc08796bfb88bc0010006f365f1361462761aa.tar.bz2
Graphics View Optimization: Use a simple style option by default.
QStyleOptionGraphicsItem extends QStyleOption with three values: 1) matrix, 2) levelOfDetail, 3) exposedRect, and they all involve expensive QTranform operations when calculated. We pass style option(s) to drawItems() and paint(), but the extended values are usually not in use. We can therefore gain quite some nice speedup by making them opt-in with the QGraphicsItem::ItemUsesExtendedStyleOption flag. Additionally, QStyleOptionGraphicsItem::levelOfDetail has been obsoleted, and a new function QStyleOptionGraphicsItem:: levelOfDetailFromTransform(const QTransform &) has been added. Me and Andreas don't consider this change to be too controversial even though it changes the behavior. Auto tests still pass. Reviewed-by: Andreas
Diffstat (limited to 'src')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp67
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h4
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h13
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp34
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp120
-rw-r--r--src/gui/graphicsview/qgraphicsview_p.h7
-rw-r--r--src/gui/graphicsview/qgraphicswidget_p.cpp1
-rw-r--r--src/gui/styles/qstyleoption.cpp44
-rw-r--r--src/gui/styles/qstyleoption.h1
9 files changed, 123 insertions, 168 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index aa55908..ec08aaf 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -274,6 +274,15 @@
this flag, the child will be stacked behind it. This flag is useful for
drop shadow effects and for decoration objects that follow the parent
item's geometry without drawing on top of it.
+
+ \value ItemUsesExtendedStyleOption The item makes use of either
+ QStyleOptionGraphicsItem::exposedRect or QStyleOptionGraphicsItem::matrix.
+ By default, the exposedRect is initialized to the item's boundingRect and
+ the matrix is untransformed. Enable this flag for more fine-grained values.
+ Note that QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag
+ and is always initialized to 1.
+ Use QStyleOptionGraphicsItem::levelOfDetailFromTransform for a more
+ fine-grained value.
*/
/*!
@@ -914,6 +923,53 @@ void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rec
}
}
+void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform,
+ const QRegion &exposedRegion, bool allItems) const
+{
+ Q_ASSERT(option);
+ Q_Q(const QGraphicsItem);
+
+ // Initialize standard QStyleOption values.
+ const QRectF brect = q->boundingRect();
+ option->state = QStyle::State_None;
+ option->rect = brect.toRect();
+ option->levelOfDetail = 1;
+ option->exposedRect = brect;
+ if (selected)
+ option->state |= QStyle::State_Selected;
+ if (enabled)
+ option->state |= QStyle::State_Enabled;
+ if (q->hasFocus())
+ option->state |= QStyle::State_HasFocus;
+ if (scene) {
+ if (scene->d_func()->hoverItems.contains(q_ptr))
+ option->state |= QStyle::State_MouseOver;
+ if (q == scene->mouseGrabberItem())
+ option->state |= QStyle::State_Sunken;
+ }
+
+ if (!(flags & QGraphicsItem::ItemUsesExtendedStyleOption))
+ return;
+
+ // Initialize QStyleOptionGraphicsItem specific values (matrix, exposedRect).
+
+ const QTransform itemToViewportTransform = q->deviceTransform(worldTransform);
+ option->matrix = itemToViewportTransform.toAffine(); //### discards perspective
+
+ if (!allItems) {
+ // Determine the item's exposed area
+ option->exposedRect = QRectF();
+ const QTransform reverseMap = itemToViewportTransform.inverted();
+ const QVector<QRect> exposedRects(exposedRegion.rects());
+ for (int i = 0; i < exposedRects.size(); ++i) {
+ option->exposedRect |= reverseMap.mapRect(exposedRects.at(i));
+ if (option->exposedRect.contains(brect))
+ break;
+ }
+ option->exposedRect &= brect;
+ }
+}
+
/*!
\internal
@@ -3671,7 +3727,7 @@ void QGraphicsItem::setBoundingRegionGranularity(qreal granularity)
All painting is done in local coordinates.
- \sa setCacheMode(), QPen::width(), {Item Coordinates}
+ \sa setCacheMode(), QPen::width(), {Item Coordinates}, ItemUsesExtendedStyleOption
*/
/*!
@@ -7635,9 +7691,7 @@ void QGraphicsPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsIte
painter->setRenderHint(QPainter::SmoothPixmapTransform,
(d->transformationMode == Qt::SmoothTransformation));
- QRectF exposed = option->exposedRect.adjusted(-1, -1, 1, 1);
- exposed &= QRectF(d->offset.x(), d->offset.y(), d->pixmap.width(), d->pixmap.height());
- painter->drawPixmap(exposed, d->pixmap, exposed.translated(-d->offset));
+ painter->drawPixmap(d->offset, d->pixmap);
if (option->state & QStyle::State_Selected)
qt_graphicsItem_highlightSelected(this, painter, option);
@@ -7803,6 +7857,7 @@ QGraphicsTextItem::QGraphicsTextItem(const QString &text, QGraphicsItem *parent
setPlainText(text);
setAcceptDrops(true);
setAcceptHoverEvents(true);
+ setFlags(ItemUsesExtendedStyleOption);
}
/*!
@@ -7822,6 +7877,7 @@ QGraphicsTextItem::QGraphicsTextItem(QGraphicsItem *parent
dd->qq = this;
setAcceptDrops(true);
setAcceptHoverEvents(true);
+ setFlag(ItemUsesExtendedStyleOption);
}
/*!
@@ -9167,6 +9223,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag)
case QGraphicsItem::ItemStacksBehindParent:
str = "ItemStacksBehindParent";
break;
+ case QGraphicsItem::ItemUsesExtendedStyleOption:
+ str = "ItemUsesExtendedStyleOption";
+ break;
}
debug << str;
return debug;
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index b98882d..0a0179e 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -94,7 +94,9 @@ public:
ItemIgnoresTransformations = 0x20,
ItemIgnoresParentOpacity = 0x40,
ItemDoesntPropagateOpacityToChildren = 0x80,
- ItemStacksBehindParent = 0x100
+ ItemStacksBehindParent = 0x100,
+ ItemUsesExtendedStyleOption = 0x200
+ // NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag.
};
Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag)
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 2936cf1..82a48fb 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -132,7 +132,6 @@ public:
ancestorFlags(0),
cacheMode(0),
hasBoundingRegionGranularity(0),
- flags(0),
hasOpacity(0),
hasEffectiveOpacity(0),
isWidget(0),
@@ -142,6 +141,7 @@ public:
dirtyClipPath(1),
emptyClipPath(0),
inSetPosHelper(0),
+ flags(0),
allChildrenCombineOpacity(1),
globalStackingOrder(-1),
sceneTransformIndex(-1),
@@ -178,6 +178,8 @@ public:
void removeChild(QGraphicsItem *child);
void setParentItemHelper(QGraphicsItem *parent, bool deleting);
void childrenBoundingRectHelper(QTransform *x, QRectF *rect);
+ void initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform,
+ const QRegion &exposedRegion, bool allItems = false) const;
virtual void resolveFont(uint inheritedMask)
{
@@ -297,7 +299,7 @@ public:
int index;
int depth;
- // Packed 32 bytes
+ // Packed 32 bits
quint32 acceptedMouseButtons : 5;
quint32 visible : 1;
quint32 explicitlyHidden : 1;
@@ -314,9 +316,6 @@ public:
quint32 ancestorFlags : 3;
quint32 cacheMode : 2;
quint32 hasBoundingRegionGranularity : 1;
- quint32 flags : 9;
-
- // New 32 bytes
quint32 hasOpacity : 1;
quint32 hasEffectiveOpacity : 1;
quint32 isWidget : 1;
@@ -326,7 +325,11 @@ public:
quint32 dirtyClipPath : 1;
quint32 emptyClipPath : 1;
quint32 inSetPosHelper : 1;
+
+ // New 32 bits
+ quint32 flags : 10;
quint32 allChildrenCombineOpacity : 1;
+ quint32 padding : 21; // feel free to use
// Optional stacking order
int globalStackingOrder;
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index c421f05..7318fa5 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -2247,8 +2247,6 @@ void QGraphicsScene::setSceneRect(const QRectF &rect)
void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRectF &source,
Qt::AspectRatioMode aspectRatioMode)
{
- Q_D(QGraphicsScene);
-
// Default source rect = scene rect
QRectF sourceRect = source;
if (sourceRect.isNull())
@@ -2305,36 +2303,8 @@ void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRect
// Generate the style options
QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems];
- for (int i = 0; i < numItems; ++i) {
- QGraphicsItem *item = itemArray[i];
-
- QStyleOptionGraphicsItem option;
- option.state = QStyle::State_None;
- option.rect = item->boundingRect().toRect();
- if (item->isSelected())
- option.state |= QStyle::State_Selected;
- if (item->isEnabled())
- option.state |= QStyle::State_Enabled;
- if (item->hasFocus())
- option.state |= QStyle::State_HasFocus;
- if (d->hoverItems.contains(item))
- option.state |= QStyle::State_MouseOver;
- if (item == mouseGrabberItem())
- option.state |= QStyle::State_Sunken;
-
- // Calculate a simple level-of-detail metric.
- // ### almost identical code in QGraphicsView::paintEvent()
- // and QGraphicsView::render() - consider refactoring
- QTransform itemToDeviceTransform = item->deviceTransform(painterTransform);
-
- option.levelOfDetail = qSqrt(itemToDeviceTransform.map(v1).length() * itemToDeviceTransform.map(v2).length());
- option.matrix = itemToDeviceTransform.toAffine(); //### discards perspective
-
- option.exposedRect = item->boundingRect();
- option.exposedRect &= itemToDeviceTransform.inverted().mapRect(targetRect);
-
- styleOptionArray[i] = option;
- }
+ for (int i = 0; i < numItems; ++i)
+ itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect());
// Render the scene.
drawBackground(painter, sourceRect);
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index 7181045..396618c 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -1127,69 +1127,6 @@ QList<QGraphicsItem *> QGraphicsViewPrivate::findItems(const QRegion &exposedReg
return itemsInArea(exposedPath, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder);
}
-void QGraphicsViewPrivate::generateStyleOptions(const QList<QGraphicsItem *> &itemList,
- QGraphicsItem **itemArray,
- QStyleOptionGraphicsItem *styleOptionArray,
- const QTransform &worldTransform,
- bool allItems,
- const QRegion &exposedRegion) const
-{
- // Two unit vectors.
- QLineF v1(0, 0, 1, 0);
- QLineF v2(0, 0, 0, 1);
- QTransform itemToViewportTransform;
- QRectF brect;
- QTransform reverseMap;
-
- for (int i = 0; i < itemList.size(); ++i) {
- QGraphicsItem *item = itemArray[i] = itemList[i];
-
- QStyleOptionGraphicsItem &option = styleOptionArray[i];
- brect = item->boundingRect();
- option.state = QStyle::State_None;
- option.rect = brect.toRect();
- option.exposedRect = QRectF();
- if (item->d_ptr->selected)
- option.state |= QStyle::State_Selected;
- if (item->d_ptr->enabled)
- option.state |= QStyle::State_Enabled;
- if (item->hasFocus())
- option.state |= QStyle::State_HasFocus;
- if (scene->d_func()->hoverItems.contains(item))
- option.state |= QStyle::State_MouseOver;
- if (item == scene->mouseGrabberItem())
- option.state |= QStyle::State_Sunken;
-
- // Calculate a simple level-of-detail metric.
- // ### almost identical code in QGraphicsScene::render()
- // and QGraphicsView::render() - consider refactoring
- itemToViewportTransform = item->deviceTransform(worldTransform);
-
- if (itemToViewportTransform.type() <= QTransform::TxTranslate) {
- // Translation and rotation only? The LOD is 1.
- option.levelOfDetail = 1;
- } else {
- // LOD is the transformed area of a 1x1 rectangle.
- option.levelOfDetail = qSqrt(itemToViewportTransform.map(v1).length() * itemToViewportTransform.map(v2).length());
- }
- option.matrix = itemToViewportTransform.toAffine(); //### discards perspective
-
- if (!allItems) {
- // Determine the item's exposed area
- reverseMap = itemToViewportTransform.inverted();
- foreach (const QRect &rect, exposedRegion.rects()) {
- option.exposedRect |= reverseMap.mapRect(QRectF(rect.adjusted(-1, -1, 1, 1)));
- if (option.exposedRect.contains(brect))
- break;
- }
- option.exposedRect &= brect;
- } else {
- // The whole item is exposed
- option.exposedRect = brect;
- }
- }
-}
-
/*!
Constructs a QGraphicsView. \a parent is passed to QWidget's constructor.
*/
@@ -2146,40 +2083,10 @@ void QGraphicsView::render(QPainter *painter, const QRectF &target, const QRect
.scale(xratio, yratio)
.translate(-sourceRect.left(), -sourceRect.top());
- // Two unit vectors.
- QLineF v1(0, 0, 1, 0);
- QLineF v2(0, 0, 0, 1);
-
// Generate the style options
QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems);
- QStyleOptionGraphicsItem* option = styleOptionArray;
- for (int i = 0; i < numItems; ++i, ++option) {
- QGraphicsItem *item = itemArray[i];
-
- option->state = QStyle::State_None;
- option->rect = item->boundingRect().toRect();
- if (item->isSelected())
- option->state |= QStyle::State_Selected;
- if (item->isEnabled())
- option->state |= QStyle::State_Enabled;
- if (item->hasFocus())
- option->state |= QStyle::State_HasFocus;
- if (d->scene->d_func()->hoverItems.contains(item))
- option->state |= QStyle::State_MouseOver;
- if (item == d->scene->mouseGrabberItem())
- option->state |= QStyle::State_Sunken;
-
- // Calculate a simple level-of-detail metric.
- // ### almost identical code in QGraphicsScene::render()
- // and QGraphicsView::paintEvent() - consider refactoring
- QTransform itemToViewportTransform = item->deviceTransform(painterMatrix);
-
- option->levelOfDetail = qSqrt(itemToViewportTransform.map(v1).length() * itemToViewportTransform.map(v2).length());
- option->matrix = itemToViewportTransform.toAffine();
-
- option->exposedRect = item->boundingRect();
- option->exposedRect &= itemToViewportTransform.inverted().mapRect(targetRect);
- }
+ for (int i = 0; i < numItems; ++i)
+ itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterMatrix, targetRect.toRect());
painter->save();
@@ -3538,15 +3445,17 @@ void QGraphicsView::paintEvent(QPaintEvent *event)
int backgroundTime = stopWatch.elapsed() - exposedTime;
#endif
- // Generate the style options
- QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
- QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(itemList.size());
-
- d->generateStyleOptions(itemList, itemArray, styleOptionArray, viewTransform,
- allItems, exposedRegion);
-
- // Items
- drawItems(&painter, itemList.size(), itemArray, styleOptionArray);
+ if (!itemList.isEmpty()) {
+ // Generate the style options.
+ const int numItems = itemList.size();
+ QGraphicsItem **itemArray = &itemList[0]; // Relies on QList internals, but is perfectly valid.
+ QStyleOptionGraphicsItem *styleOptionArray = d->allocStyleOptionsArray(numItems);
+ for (int i = 0; i < numItems; ++i)
+ itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], viewTransform, exposedRegion, allItems);
+ // Draw the items.
+ drawItems(&painter, numItems, itemArray, styleOptionArray);
+ d->freeStyleOptionsArray(styleOptionArray);
+ }
#ifdef QGRAPHICSVIEW_DEBUG
int itemsTime = stopWatch.elapsed() - exposedTime - backgroundTime;
@@ -3555,9 +3464,6 @@ void QGraphicsView::paintEvent(QPaintEvent *event)
// Foreground
drawForeground(&painter, exposedSceneRect);
- delete [] itemArray;
- d->freeStyleOptionsArray(styleOptionArray);
-
#ifdef QGRAPHICSVIEW_DEBUG
int foregroundTime = stopWatch.elapsed() - exposedTime - backgroundTime - itemsTime;
#endif
diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h
index d573e8f..c18f85d 100644
--- a/src/gui/graphicsview/qgraphicsview_p.h
+++ b/src/gui/graphicsview/qgraphicsview_p.h
@@ -174,13 +174,6 @@ public:
bool updateSceneSlotReimplementedChecked;
QList<QGraphicsItem *> findItems(const QRegion &exposedRegion, bool *allItems) const;
-
- void generateStyleOptions(const QList<QGraphicsItem *> &itemList,
- QGraphicsItem **itemArray,
- QStyleOptionGraphicsItem *styleOptionArray,
- const QTransform &worldTransform,
- bool allItems,
- const QRegion &exposedRegion) const;
};
QT_END_NAMESPACE
diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp
index 8ced47a..a435758 100644
--- a/src/gui/graphicsview/qgraphicswidget_p.cpp
+++ b/src/gui/graphicsview/qgraphicswidget_p.cpp
@@ -76,6 +76,7 @@ void QGraphicsWidgetPrivate::init(QGraphicsItem *parentItem, Qt::WindowFlags wFl
resolveLayoutDirection();
q->unsetWindowFrameMargins();
+ q->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
}
qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const
{
diff --git a/src/gui/styles/qstyleoption.cpp b/src/gui/styles/qstyleoption.cpp
index ce053ae..5b1bc61 100644
--- a/src/gui/styles/qstyleoption.cpp
+++ b/src/gui/styles/qstyleoption.cpp
@@ -48,6 +48,7 @@
#ifndef QT_NO_DEBUG
#include <qdebug.h>
#endif
+#include <QtCore/qmath.h>
QT_BEGIN_NAMESPACE
@@ -4998,6 +4999,34 @@ QStyleOptionGraphicsItem::QStyleOptionGraphicsItem(int version)
}
/*!
+ \since 4.6
+
+ Returns the level of detail from the \a worldTransform.
+
+ Its value represents the maximum value of the height and
+ width of a unity rectangle, mapped using the \a worldTransform
+ of the painter used to draw the item. By default, if no
+ transformations are applied, its value is 1. If zoomed out 1:2, the level
+ of detail will be 0.5, and if zoomed in 2:1, its value is 2.
+
+ For more advanced level-of-detail metrics, use
+ QStyleOptionGraphicsItem::matrix directly.
+
+ \sa QStyleOptionGraphicsItem::matrix
+*/
+qreal QStyleOptionGraphicsItem::levelOfDetailFromTransform(const QTransform &worldTransform)
+{
+ if (worldTransform.type() <= QTransform::TxTranslate)
+ return 1; // Translation only? The LOD is 1.
+
+ // Two unit vectors.
+ QLineF v1(0, 0, 1, 0);
+ QLineF v2(0, 0, 0, 1);
+ // LOD is the transformed area of a 1x1 rectangle.
+ return qSqrt(worldTransform.map(v1).length() * worldTransform.map(v2).length());
+}
+
+/*!
\fn QStyleOptionGraphicsItem::QStyleOptionGraphicsItem(const QStyleOptionGraphicsItem &other)
Constructs a copy of \a other.
@@ -5029,19 +5058,10 @@ QStyleOptionGraphicsItem::QStyleOptionGraphicsItem(int version)
/*!
\variable QStyleOptionGraphicsItem::levelOfDetail
- \brief a simple metric for determining an item's level of detail
-
- This simple metric provides an easy way to determine the level of detail
- for an item. Its value represents the maximum value of the height and
- width of a unity rectangle, mapped using the complete transformation
- matrix of the painter used to draw the item. By default, if no
- transformations are applied, its value is 1. If zoomed out 1:2, the level
- of detail will be 0.5, and if zoomed in 2:1, its value is 2.
-
- For more advanced level-of-detail metrics, use
- QStyleOptionGraphicsItem::matrix directly.
+ \obsolete
- \sa QStyleOptionGraphicsItem::matrix
+ Use QStyleOptionGraphicsItem::levelOfDetailFromTransform
+ together with QPainter::worldTransform() instead.
*/
/*!
diff --git a/src/gui/styles/qstyleoption.h b/src/gui/styles/qstyleoption.h
index 5759a05..eb05324 100644
--- a/src/gui/styles/qstyleoption.h
+++ b/src/gui/styles/qstyleoption.h
@@ -856,6 +856,7 @@ public:
QStyleOptionGraphicsItem();
QStyleOptionGraphicsItem(const QStyleOptionGraphicsItem &other) : QStyleOption(Version, Type) { *this = other; }
+ static qreal levelOfDetailFromTransform(const QTransform &worldTransform);
protected:
QStyleOptionGraphicsItem(int version);
};