diff options
author | Stanislav Ionascu <stanislav.ionascu@nokia.com> | 2010-07-19 16:10:05 +0300 |
---|---|---|
committer | Sergiy Dubovik <sergiy.dubovik@nokia.com> | 2010-07-21 13:14:04 +0300 |
commit | 0cc8bab7a60adcac984559da8660efa16e605875 (patch) | |
tree | b5ec1c273d60842b2f12917f348a3489754181b6 | |
parent | 0e733e08291da0a1adcd5edbf0620331f4f16aa6 (diff) |
Changes: Make MImageWidget draw the QImage instead of transforming it into QPixmap.
RevBy: Sergiy
Details: QPixmap::fromImage is a very slow operation on X11, so use QImage for drawing
instead of transforming it on each set into QPixmap.
Also do not calculate source and draw rectangles on each draw contents call. Because
it will be recalculated on each draw pass.
Some major refactoring involved such as separating draw, source rectangle calculations in
their own functions. Refactored border draw code into own function, added caching of style
parameters.
-rw-r--r-- | src/corelib/widgets/mimagewidget.cpp | 45 | ||||
-rw-r--r-- | src/corelib/widgets/mimagewidget_p.h | 7 | ||||
-rw-r--r-- | src/views/mimagewidgetview.cpp | 244 | ||||
-rw-r--r-- | src/views/mimagewidgetview.h | 3 | ||||
-rw-r--r-- | src/views/mimagewidgetview_p.h | 64 |
5 files changed, 256 insertions, 107 deletions
diff --git a/src/corelib/widgets/mimagewidget.cpp b/src/corelib/widgets/mimagewidget.cpp index 9ef6edb5..7ea7eb95 100644 --- a/src/corelib/widgets/mimagewidget.cpp +++ b/src/corelib/widgets/mimagewidget.cpp @@ -50,6 +50,7 @@ void MImageWidgetPrivate::cleanUp() MTheme::releasePixmap(pixmap); pixmap = 0; } + image = QImage(); } QSizeF MImageWidgetPrivate::imageDataSize() const @@ -57,11 +58,15 @@ QSizeF MImageWidgetPrivate::imageDataSize() const Q_Q(const MImageWidget); QSizeF imageSize = QSizeF(0, 0); - if (pixmap != 0 && !pixmap->isNull()) { - if (q->model()->crop().isEmpty()) - imageSize = pixmap->size(); - else + if ((pixmap != 0 && !pixmap->isNull()) || (!image.isNull())) { + if (q->model()->crop().isEmpty()) { + if (image.isNull()) + imageSize = pixmap->size(); + else + imageSize = image.size(); + } else { imageSize = q->model()->crop().size(); + } } return imageSize; @@ -72,8 +77,12 @@ MImageWidgetPrivate &MImageWidgetPrivate::operator=(const MImageWidgetPrivate &o cleanUp(); if (other.pixmap != 0) { - if (other.deletePixmap) - pixmap = new QPixmap(*(other.pixmap)); + if (other.deletePixmap) { + if (other.pixmap) + pixmap = new QPixmap(*(other.pixmap)); + else + image = other.image; + } else setImageName(other.imageName, other.pixmap->size()); } @@ -130,7 +139,8 @@ MImageWidget::MImageWidget(const QImage *image, QGraphicsItem *parent) : MWidgetController(new MImageWidgetPrivate(), new MImageWidgetModel(), parent) { Q_D(MImageWidget); - d->pixmap = new QPixmap(QPixmap::fromImage(*image)); + d->pixmap = NULL; + d->image = *image; } MImageWidget::MImageWidget(const QPixmap *pixmap, QGraphicsItem *parent) : @@ -180,6 +190,8 @@ QSize MImageWidget::imageSize() const Q_D(const MImageWidget); if (d->pixmap != 0) return d->pixmap->size(); + else + return d->image.size(); return QSize(); } @@ -217,7 +229,8 @@ void MImageWidget::zoomFactor(qreal *fx, qreal *fy) const Q_D(const MImageWidget); QSizeF imageSize = d->imageDataSize(); - if (imageSize.isEmpty()) return; + if (imageSize.isEmpty()) + return; // if factor not equals 0, calculate it with imageSize, targetSize and widgetSize QSizeF buffer; @@ -267,7 +280,8 @@ void MImageWidget::zoomOut() void MImageWidget::setAspectRatioMode(Qt::AspectRatioMode mode) { - if (model()->aspectRatioMode() == mode) return; + if (model()->aspectRatioMode() == mode) + return; model()->setAspectRatioMode(mode); } @@ -279,10 +293,13 @@ Qt::AspectRatioMode MImageWidget::aspectRatioMode() const void MImageWidget::setCrop(const QRectF &rect) { Q_D(MImageWidget); - if (d->pixmap == 0) return; - if (rect.size().width() < 0 || rect.size().height() < 0) return; + if (d->pixmap == 0 && d->image.isNull()) + return; - QSizeF imageSize = d->pixmap->size(); + if (rect.size().width() < 0 || rect.size().height() < 0) + return; + + QSizeF imageSize = this->imageSize(); // protect the crop section size not beyond the image size QRectF r; @@ -330,8 +347,8 @@ void MImageWidget::setImage(const QImage &image) Q_D(MImageWidget); d->cleanUp(); - d->pixmap = new QPixmap(QPixmap::fromImage(image)); - d->deletePixmap = true; + d->image = image; + d->deletePixmap = false; model()->setCrop(QRect()); diff --git a/src/corelib/widgets/mimagewidget_p.h b/src/corelib/widgets/mimagewidget_p.h index 4b3bc3bc..aed5b174 100644 --- a/src/corelib/widgets/mimagewidget_p.h +++ b/src/corelib/widgets/mimagewidget_p.h @@ -40,10 +40,11 @@ public: void deepCopy(const MImageWidget &); - const QPixmap *pixmap; - QString imageName; + const QPixmap *pixmap; + QString imageName; + QImage image; - bool deletePixmap; + bool deletePixmap; }; #endif diff --git a/src/views/mimagewidgetview.cpp b/src/views/mimagewidgetview.cpp index 4ba442e6..b780ced1 100644 --- a/src/views/mimagewidgetview.cpp +++ b/src/views/mimagewidgetview.cpp @@ -18,6 +18,7 @@ ****************************************************************************/ #include "mimagewidgetview.h" +#include "mimagewidgetview_p.h" #include <QPixmap> @@ -26,17 +27,15 @@ #include "mviewcreator.h" #include "private/mwidgetview_p.h" -class MImageWidgetViewPrivate : public MWidgetViewPrivate -{ -public: - MImageWidgetViewPrivate(); - ~MImageWidgetViewPrivate(); - - MImageWidget *controller; -}; - MImageWidgetViewPrivate::MImageWidgetViewPrivate() - : controller(0) + : controller(NULL), + cachedPixmapSize(0, 0), + borderOpacity(1.0), + brush(Qt::transparent), + leftBorder(0.0), + topBorder(0.0), + rightBorder(0.0), + bottomBorder(0.0) { } @@ -44,45 +43,53 @@ MImageWidgetViewPrivate::~MImageWidgetViewPrivate() { } -MImageWidgetView::MImageWidgetView(MImageWidget *controller) : - MWidgetView(* new MImageWidgetViewPrivate, controller) +void MImageWidgetViewPrivate::calculateDrawRect(const QSizeF &imageSize) { - Q_D(MImageWidgetView); - d->controller = controller; -} + Q_Q(MImageWidgetView); -MImageWidgetView::MImageWidgetView(MImageWidgetViewPrivate &dd, MImageWidget *controller) : - MWidgetView(dd, controller) -{ - Q_D(MImageWidgetView); - d->controller = controller; -} + // no image, return + if (imageSize.isEmpty()) + return; -MImageWidgetView::~MImageWidgetView() -{ -} + // get target size, bounded by widget size + QSizeF widgetSize = q->size(); + QSizeF targetSize = widgetSize; + QSizeF t; -void MImageWidgetView::drawContents(QPainter *painter, const QStyleOptionGraphicsItem *option) const -{ - Q_UNUSED(option); + // get the image display size + qreal fx, fy; + controller->zoomFactor(&fx, &fy); - Q_D(const MImageWidgetView); + t.setWidth(imageSize.width()*fx); + t.setHeight(imageSize.height()*fy); - // no image, return - QSizeF imageSize = d->controller->d_func()->imageDataSize(); - if (imageSize.isEmpty()) return; + // limited by target size + t = targetSize.boundedTo(t); + + // calculate the rectangle of draw + qreal dx = (widgetSize.width() - t.width()) / 2.0; + qreal dy = (widgetSize.height() - t.height()) / 2.0; - // the source image section size will be used finally + // calculate draw rect + drawRect.setRect(dx, dy, t.width(), t.height()); +} + +QSizeF MImageWidgetViewPrivate::calculateSourceSize(const QSizeF &imageSize) +{ QSizeF sourceSize = imageSize; + QSizeF targetSize = controller->size(); + + // protection codes + if (sourceSize.width() < 1.0) + sourceSize.setWidth(1.0); + if (sourceSize.height() < 1.0) + sourceSize.setHeight(1.0); - // get target size, bounded by widget size - QSizeF widgetSize = size(); - QSizeF targetSize = widgetSize; QSizeF t; // get the image display size qreal fx, fy; - d->controller->zoomFactor(&fx, &fy); + controller->zoomFactor(&fx, &fy); t.setWidth(imageSize.width()*fx); t.setHeight(imageSize.height()*fy); @@ -98,57 +105,55 @@ void MImageWidgetView::drawContents(QPainter *painter, const QStyleOptionGraphic sourceSize.setHeight(qRound(value * targetSize.height() / t.height())); } - // limited by target size - t = targetSize.boundedTo(t); - - // protection codes - if (sourceSize.width() < 1.0) - sourceSize.setWidth(1.0); - if (sourceSize.height() < 1.0) - sourceSize.setHeight(1.0); - - // get values from controller - const QPixmap *pixmap = d->controller->pixmap(); + return sourceSize; +} - qreal leftBorder = style()->borderLeft(); - qreal topBorder = style()->borderTop(); - qreal rightBorder = style()->borderRight(); - qreal bottomBorder = style()->borderBottom(); +void MImageWidgetViewPrivate::calculateSourceRect(const QSizeF &imageSize) +{ + QPointF topLeft = controller->crop().topLeft(); + QSizeF originalSize = controller->imageSize(); + QSizeF sourceSize = calculateSourceSize(imageSize); - qreal w = leftBorder + rightBorder; - qreal h = topBorder + bottomBorder; + if (topLeft == QPointF(-1.0, -1.0)) { + // calculate default crop section + qreal dx = (originalSize.width() - sourceSize.width()) / 2.0; + qreal dy = (originalSize.height() - sourceSize.height()) / 2.0; - // calculate if need draw border - // notice: no border on the cropped edge - QSizeF originSize = pixmap->size(); + sourceRect = QRectF(dx, dy, sourceSize.width(), sourceSize.height()); + } else { + // calculate crop section by given topLeft corner + qreal dx = topLeft.x(); + qreal dy = topLeft.y(); - if (originSize.width() > sourceSize.width()) - w = 0; + sourceRect = QRectF(dx, dy, qMin(dx + sourceSize.width(), originalSize.width()), + qMin(dy + sourceSize.height(), originalSize.height())); + } +} - if (originSize.height() > sourceSize.height()) - h = 0; +void MImageWidgetViewPrivate::checkPixmapSize() +{ + Q_Q(MImageWidgetView); - // calculate the rectangle of draw - qreal dx = (widgetSize.width() - t.width()) / 2.0; - qreal dy = (widgetSize.height() - t.height()) / 2.0; + const QPixmap *pixmap = controller->pixmap(); + if (pixmap->size() != cachedPixmapSize) { + cachedPixmapSize = pixmap->size(); + q->updateGeometry(); + } +} - // calculate draw rect - QRectF drawRect, sourceRect, border; - drawRect.setRect(dx, dy, t.width(), t.height()); +void MImageWidgetViewPrivate::drawBorders(QPainter *painter, const QRectF &drawRect) const +{ + qreal w = leftBorder + rightBorder; + qreal h = topBorder + bottomBorder; - // draw borders outside of target - // if both borders equals 0, do not draw border if (w > 0 || h > 0) { - - QColor borderColor = style()->borderColor(); - qreal borderOpacity = style()->borderOpacity(); - QBrush brush(borderColor); + QRectF border; qreal oldOpacity = painter->opacity(); painter->setOpacity(borderOpacity); - dx = drawRect.x() - leftBorder; - dy = drawRect.y() - topBorder; + qreal dx = drawRect.x() - leftBorder; + qreal dy = drawRect.y() - topBorder; if (w > 0 && h == 0) { // only have horizontal border @@ -165,7 +170,6 @@ void MImageWidgetView::drawContents(QPainter *painter, const QStyleOptionGraphic border = QRectF(drawRect.x(), drawRect.y() + drawRect.height(), drawRect.width(), bottomBorder); painter->fillRect(border, brush); } else { - // draw top border border = QRectF(dx, dy, drawRect.width() + w, topBorder); painter->fillRect(border, brush); @@ -185,27 +189,56 @@ void MImageWidgetView::drawContents(QPainter *painter, const QStyleOptionGraphic painter->setOpacity(oldOpacity); } - // draw image - QPointF topLeft = d->controller->crop().topLeft(); +} - if (topLeft == QPointF(-1.0, -1.0)) { +void MImageWidgetViewPrivate::applyStyle() +{ + Q_Q(MImageWidgetView); - // calculate default crop section - dx = (originSize.width() - sourceSize.width()) / 2.0; - dy = (originSize.height() - sourceSize.height()) / 2.0; + borderOpacity = q->style()->borderOpacity(); + brush.setColor(q->style()->borderColor()); - sourceRect = QRectF(dx, dy, sourceSize.width(), sourceSize.height()); - } else { + leftBorder = q->style()->borderLeft(); + topBorder = q->style()->borderTop(); + rightBorder = q->style()->borderRight(); + bottomBorder = q->style()->borderBottom(); +} - // calculate crop section by given topLeft corner - dx = topLeft.x(); - dy = topLeft.y(); +MImageWidgetView::MImageWidgetView(MImageWidget *controller) : + MWidgetView(* new MImageWidgetViewPrivate, controller) +{ + Q_D(MImageWidgetView); + d->controller = controller; +} - sourceRect = QRectF(dx, dy, qMin(dx + sourceSize.width(), originSize.width()), - qMin(dy + sourceSize.height(), originSize.height())); - } +MImageWidgetView::MImageWidgetView(MImageWidgetViewPrivate &dd, MImageWidget *controller) : + MWidgetView(dd, controller) +{ + Q_D(MImageWidgetView); + d->controller = controller; +} - painter->drawPixmap(drawRect, *pixmap, sourceRect); +MImageWidgetView::~MImageWidgetView() +{ +} + +void MImageWidgetView::drawContents(QPainter *painter, const QStyleOptionGraphicsItem *option) const +{ + Q_UNUSED(option); + + Q_D(const MImageWidgetView); + + const QPixmap *pixmap = d->controller->pixmap(); + + d->drawBorders(painter, d->drawRect); + + if (pixmap) { + const_cast<MImageWidgetViewPrivate*>(d)->checkPixmapSize(); + painter->drawPixmap(d->drawRect, *pixmap, d->sourceRect); + } else { + QImage image = d->controller->d_func()->image; + painter->drawImage(d->drawRect, image, d->sourceRect); + } } void MImageWidgetView::resizeEvent(QGraphicsSceneResizeEvent *event) @@ -214,6 +247,37 @@ void MImageWidgetView::resizeEvent(QGraphicsSceneResizeEvent *event) update(); } +void MImageWidgetView::setGeometry(const QRectF &rect) +{ + Q_D(MImageWidgetView); + MWidgetView::setGeometry(rect); + + QSizeF imageSize = d->controller->d_func()->imageDataSize(); + d->calculateDrawRect(imageSize); + d->calculateSourceRect(imageSize); +} + +void MImageWidgetView::applyStyle() +{ + Q_D(MImageWidgetView); + MWidgetView::applyStyle(); + + d->applyStyle(); +} + +void MImageWidgetView::updateData(const QList<const char *> &modifications) +{ + MWidgetView::updateData(modifications); + + const char *member; + for (int i = 0; i < modifications.count(); i++) { + member = modifications[i]; + if (member == MImageWidgetModel::ZoomFactorX || member == MImageWidgetModel::ZoomFactorY || member == MImageWidgetModel::Crop) { + updateGeometry(); + } + } +} + QSizeF MImageWidgetView::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const { Q_D(const MImageWidgetView); diff --git a/src/views/mimagewidgetview.h b/src/views/mimagewidgetview.h index 0f1d0040..fd4c80e0 100644 --- a/src/views/mimagewidgetview.h +++ b/src/views/mimagewidgetview.h @@ -72,6 +72,9 @@ protected: //! \reimp virtual void drawContents(QPainter *painter, const QStyleOptionGraphicsItem *option) const; virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const; + virtual void setGeometry(const QRectF &rect); + virtual void applyStyle(); + virtual void updateData(const QList<const char *> &modifications); //! \reimp_end //! \internal diff --git a/src/views/mimagewidgetview_p.h b/src/views/mimagewidgetview_p.h new file mode 100644 index 00000000..569643b4 --- /dev/null +++ b/src/views/mimagewidgetview_p.h @@ -0,0 +1,64 @@ +/*************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (directui@nokia.com) +** +** This file is part of libmeegotouch. +** +** If you have questions regarding the use of this file, please contact +** Nokia at directui@nokia.com. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation +** and appearing in the file LICENSE.LGPL included in the packaging +** of this file. +** +****************************************************************************/ + +#ifndef MIMAGEWIDGETVIEW_P_H +#define MIMAGEWIDGETVIEW_P_H + +#include "private/mwidgetview_p.h" + +class MImageWidget; + +class MImageWidgetViewPrivate : public MWidgetViewPrivate +{ +public: + MImageWidgetViewPrivate(); + ~MImageWidgetViewPrivate(); + + void calculateDrawRect(const QSizeF &imageSize); + QSizeF calculateSourceSize(const QSizeF &imageSize); + void calculateSourceRect(const QSizeF &imageSize); + + void checkPixmapSize(); + + void drawBorders(QPainter *painter, const QRectF &drawRect) const; + + void applyStyle(); + + + QRectF drawRect; + QRectF sourceRect; + +private: + Q_DECLARE_PUBLIC(MImageWidgetView) + MImageWidget *controller; + + QSize cachedPixmapSize; + + //border related + qreal borderOpacity; + QBrush brush; + + qreal leftBorder; + qreal topBorder; + qreal rightBorder; + qreal bottomBorder; +}; + + +#endif // MIMAGEWIDGETVIEW_P_H |