diff options
author | Bjoern Erik Nilsen <bjorn.nilsen@nokia.com> | 2009-05-08 14:00:57 (GMT) |
---|---|---|
committer | Bjørn Erik Nilsen <bjorn.nilsen@nokia.com> | 2009-05-15 15:55:44 (GMT) |
commit | 59cc08796bfb88bc0010006f365f1361462761aa (patch) | |
tree | 44eebedc40e44546a5788cfb3ac497f1bab7e7d6 /src/gui/graphicsview | |
parent | b0095f7f8925cf571224d348124f08c56f7f46e9 (diff) | |
download | Qt-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/gui/graphicsview')
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 67 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.h | 4 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 13 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 34 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview.cpp | 120 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview_p.h | 7 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicswidget_p.cpp | 1 |
7 files changed, 90 insertions, 156 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 { |