diff options
author | Warwick Allison <warwick.allison@nokia.com> | 2010-03-26 04:33:04 (GMT) |
---|---|---|
committer | Warwick Allison <warwick.allison@nokia.com> | 2010-03-26 04:36:50 (GMT) |
commit | 09a40e13174b9f34007ce9fbd98e06b4e48c1954 (patch) | |
tree | 8f7735640e87e154d434f80130ab8812e3f4e58b /src | |
parent | c2928bfdb467d7c54a97a71b6a1169db02e623fe (diff) | |
download | Qt-09a40e13174b9f34007ce9fbd98e06b4e48c1954.zip Qt-09a40e13174b9f34007ce9fbd98e06b4e48c1954.tar.gz Qt-09a40e13174b9f34007ce9fbd98e06b4e48c1954.tar.bz2 |
Control of image rendered size (esp. SVG).
Add Translate transform.
Image::sourceWidth and Image::sourceHeight read/write properties.
Task-number: QTBUG-8984
Diffstat (limited to 'src')
12 files changed, 514 insertions, 78 deletions
diff --git a/src/declarative/graphicsitems/graphicsitems.pri b/src/declarative/graphicsitems/graphicsitems.pri index d30651b..af76a67 100644 --- a/src/declarative/graphicsitems/graphicsitems.pri +++ b/src/declarative/graphicsitems/graphicsitems.pri @@ -39,6 +39,7 @@ HEADERS += \ $$PWD/qdeclarativerepeater_p.h \ $$PWD/qdeclarativerepeater_p_p.h \ $$PWD/qdeclarativescalegrid_p_p.h \ + $$PWD/qdeclarativetranslate_p.h \ $$PWD/qdeclarativetextinput_p.h \ $$PWD/qdeclarativetextinput_p_p.h \ $$PWD/qdeclarativetextedit_p.h \ @@ -75,6 +76,7 @@ SOURCES += \ $$PWD/qdeclarativerectangle.cpp \ $$PWD/qdeclarativerepeater.cpp \ $$PWD/qdeclarativescalegrid.cpp \ + $$PWD/qdeclarativetranslate.cpp \ $$PWD/qdeclarativetextinput.cpp \ $$PWD/qdeclarativetext.cpp \ $$PWD/qdeclarativetextedit.cpp \ diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp index f92c207..96f95f2 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp @@ -217,7 +217,8 @@ void QDeclarativeBorderImage::load() thisSciRequestFinished, Qt::DirectConnection); } } else { - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->pix, d->async); + QSize impsize; + QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->pix, &impsize, d->async); if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) { QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->url); d->pendingPixmapCache = true; @@ -226,8 +227,8 @@ void QDeclarativeBorderImage::load() this, SLOT(requestProgress(qint64,qint64))); } else { //### should be unified with requestFinished - setImplicitWidth(d->pix.width()); - setImplicitHeight(d->pix.height()); + setImplicitWidth(impsize.width()); + setImplicitHeight(impsize.height()); if (d->pix.isNull()) d->status = Error; @@ -336,7 +337,8 @@ void QDeclarativeBorderImage::setGridScaledImage(const QDeclarativeGridScaledIma d->verticalTileMode = sci.verticalTileRule(); d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl())); - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->sciurl, &d->pix, d->async); + QSize impsize; + QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->sciurl, &d->pix, &impsize, d->async); if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) { QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->sciurl); d->sciPendingPixmapCache = true; @@ -362,8 +364,8 @@ void QDeclarativeBorderImage::setGridScaledImage(const QDeclarativeGridScaledIma thisRequestProgress, Qt::DirectConnection); } else { //### should be unified with requestFinished - setImplicitWidth(d->pix.width()); - setImplicitHeight(d->pix.height()); + setImplicitWidth(impsize.width()); + setImplicitHeight(impsize.height()); if (d->pix.isNull()) d->status = Error; @@ -381,16 +383,17 @@ void QDeclarativeBorderImage::requestFinished() { Q_D(QDeclarativeBorderImage); + QSize impsize; if (d->url.path().endsWith(QLatin1String(".sci"))) { d->sciPendingPixmapCache = false; - QDeclarativePixmapCache::get(d->sciurl, &d->pix, d->async); + QDeclarativePixmapCache::get(d->sciurl, &d->pix, &impsize, d->async); } else { d->pendingPixmapCache = false; - if (QDeclarativePixmapCache::get(d->url, &d->pix, d->async) != QDeclarativePixmapReply::Ready) + if (QDeclarativePixmapCache::get(d->url, &d->pix, &impsize, d->async) != QDeclarativePixmapReply::Ready) d->status = Error; } - setImplicitWidth(d->pix.width()); - setImplicitHeight(d->pix.height()); + setImplicitWidth(impsize.width()); + setImplicitHeight(impsize.height()); if (d->status == Loading) d->status = Ready; diff --git a/src/declarative/graphicsitems/qdeclarativeimage.cpp b/src/declarative/graphicsitems/qdeclarativeimage.cpp index 425976f..8b93063 100644 --- a/src/declarative/graphicsitems/qdeclarativeimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimage.cpp @@ -266,6 +266,32 @@ qreal QDeclarativeImage::paintedHeight() const filtering at the beginning of the animation and reenable it at the conclusion. */ +/*! + \qmlproperty int Image::sourceWidth + \qmlproperty int Image::sourceHeight + + These properties are the size of the loaded image, in pixels. + + If you set these properties explicitly, you can to control the storage + used by a loaded image. The image will be scaled down if its intrinsic size + is greater than these values. + + Unlike setting the width and height properties, which merely scale the painting + of the image, these properties affect the number of pixels stored. + + \e{Changing these properties dynamically will lead to the image source being reloaded, + potentially even from the network if it is not in the disk cache.} + + If the source is an instrinsically scalable image (eg. SVG), these properties + determine the size of the loaded image regardless of intrinsic size. You should + avoid changing these properties dynamically - rendering an SVG is \e slow compared + to an image. + + If the source is a non-scalable image (eg. JPEG), the loaded image will + be no greater than these properties specify. For some formats (currently only JPEG), + the whole image will never actually be loaded into memory. +*/ + void QDeclarativeImage::updatePaintedGeometry() { Q_D(QDeclarativeImage); diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp index e65c9d1..3b75a85 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp @@ -116,6 +116,41 @@ void QDeclarativeImageBase::setSource(const QUrl &url) load(); } +void QDeclarativeImageBase::setSourceWidth(int w) +{ + Q_D(QDeclarativeImageBase); + if (d->sourcewidth == w) + return; + d->sourcewidth = w; + emit sourceSizeChanged(); + if (isComponentComplete()) + load(); +} + +int QDeclarativeImageBase::sourceWidth() const +{ + Q_D(const QDeclarativeImageBase); + return d->sourcewidth <= 0 ? implicitWidth() : d->sourcewidth; +} + +void QDeclarativeImageBase::setSourceHeight(int h) +{ + Q_D(QDeclarativeImageBase); + if (d->sourceheight == h) + return; + d->sourceheight = h; + emit sourceSizeChanged(); + if (isComponentComplete()) + load(); +} + +int QDeclarativeImageBase::sourceHeight() const +{ + Q_D(const QDeclarativeImageBase); + return d->sourceheight <= 0 ? implicitHeight() : d->sourceheight; +} + + void QDeclarativeImageBase::load() { Q_D(QDeclarativeImageBase); @@ -134,9 +169,12 @@ void QDeclarativeImageBase::load() update(); } else { d->status = Loading; - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->pix, d->async); + int reqwidth = d->sourcewidth; + int reqheight = d->sourceheight; + QSize impsize; + QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->pix, &impsize, d->async, reqwidth, reqheight); if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) { - QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->url); + QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->url, reqwidth, reqheight); d->pendingPixmapCache = true; static int replyDownloadProgress = -1; @@ -161,11 +199,14 @@ void QDeclarativeImageBase::load() } else { //### should be unified with requestFinished if (status == QDeclarativePixmapReply::Ready) { - setImplicitWidth(d->pix.width()); - setImplicitHeight(d->pix.height()); + setImplicitWidth(impsize.width()); + setImplicitHeight(impsize.height()); if (d->status == Loading) d->status = Ready; + + if (d->sourcewidth <= 0 || d->sourceheight <= 0) + emit sourceSizeChanged(); } else { d->status = Error; } @@ -186,16 +227,19 @@ void QDeclarativeImageBase::requestFinished() d->pendingPixmapCache = false; - if (QDeclarativePixmapCache::get(d->url, &d->pix, d->async) != QDeclarativePixmapReply::Ready) + QSize impsize; + if (QDeclarativePixmapCache::get(d->url, &d->pix, &impsize, d->async, d->sourcewidth, d->sourceheight) != QDeclarativePixmapReply::Ready) d->status = Error; - setImplicitWidth(d->pix.width()); - setImplicitHeight(d->pix.height()); + setImplicitWidth(impsize.width()); + setImplicitHeight(impsize.height()); if (d->status == Loading) d->status = Ready; d->progress = 1.0; emit statusChanged(d->status); emit progressChanged(1.0); + if (d->sourcewidth <= 0 || d->sourceheight <= 0) + emit sourceSizeChanged(); pixmapChange(); update(); } diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p.h index b215193..2653d0a 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p.h @@ -59,6 +59,9 @@ class Q_DECLARATIVE_EXPORT QDeclarativeImageBase : public QDeclarativeItem Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged) + Q_PROPERTY(int sourceWidth READ sourceWidth WRITE setSourceWidth NOTIFY sourceSizeChanged) + Q_PROPERTY(int sourceHeight READ sourceHeight WRITE setSourceHeight NOTIFY sourceSizeChanged) + public: ~QDeclarativeImageBase(); enum Status { Null, Ready, Loading, Error }; @@ -71,8 +74,14 @@ public: bool asynchronous() const; void setAsynchronous(bool); + void setSourceWidth(int); + int sourceWidth() const; + void setSourceHeight(int); + int sourceHeight() const; + Q_SIGNALS: void sourceChanged(const QUrl &); + void sourceSizeChanged(); void statusChanged(Status); void progressChanged(qreal progress); void asynchronousChanged(); diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h index c4a61f3..cced228 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h @@ -68,6 +68,7 @@ public: QDeclarativeImageBasePrivate() : status(QDeclarativeImageBase::Null), progress(0.0), + sourcewidth(0), sourceheight(0), pendingPixmapCache(false), async(false) { @@ -78,6 +79,7 @@ public: QDeclarativeImageBase::Status status; QUrl url; qreal progress; + int sourcewidth, sourceheight; bool pendingPixmapCache : 1; bool async : 1; }; diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp index dd6056e..c331af7 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp @@ -83,7 +83,43 @@ QT_BEGIN_NAMESPACE You can assign any number of Transform elements to an Item. Each Transform is applied in order, one at a time, to the Item it's assigned to. - \sa Rotation, Scale + \sa Rotation, Scale, Translate +*/ + +/*! + \qmlclass Translate QGraphicsTranslate + \since 4.7 + \brief The Translate object provides a way to move an Item without changing its x or y. + + The Translate object independent control over position in addition to the Item's x and y properties. + + The following example moves the X axis of the Rectangle, relative to its interior point 25, 25: + \qml + Row { + Rectangle { + width: 100; height: 100 + color: "blue" + transform: Translate { y: 20 } + } + Rectangle { + width: 100; height: 100 + color: "red" + transform: Translate { y: -20 } + } + } + \endqml +*/ + +/*! + \qmlproperty real Translate::x + + The translation along the X axis. +*/ + +/*! + \qmlproperty real Translate::yTranslate + + The translation along the Y axis. */ /*! diff --git a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp index 07d7f4d..1c458b1d4 100644 --- a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp @@ -69,6 +69,7 @@ #include "qdeclarativepathview_p.h" #include "qdeclarativerectangle_p.h" #include "qdeclarativerepeater_p.h" +#include "qdeclarativetranslate_p.h" #include "qdeclarativetext_p.h" #include "qdeclarativetextedit_p.h" #include "qdeclarativetextinput_p.h" @@ -123,6 +124,7 @@ void QDeclarativeItemModule::defineModule() qmlRegisterType<QDeclarativeRepeater>("Qt",4,6,"Repeater"); qmlRegisterType<QGraphicsRotation>("Qt",4,6,"Rotation"); qmlRegisterType<QDeclarativeRow>("Qt",4,6,"Row"); + qmlRegisterType<QDeclarativeTranslate>("Qt",4,6,"Translate"); qmlRegisterType<QGraphicsScale>("Qt",4,6,"Scale"); qmlRegisterType<QDeclarativeText>("Qt",4,6,"Text"); qmlRegisterType<QDeclarativeTextEdit>("Qt",4,6,"TextEdit"); diff --git a/src/declarative/graphicsitems/qdeclarativetranslate.cpp b/src/declarative/graphicsitems/qdeclarativetranslate.cpp new file mode 100644 index 0000000..57c47f0 --- /dev/null +++ b/src/declarative/graphicsitems/qdeclarativetranslate.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used 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. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativetranslate_p.h" +#include <private/qgraphicstransform_p.h> +#include <QDebug> +#include <QtCore/qmath.h> + +class QDeclarativeTranslatePrivate : public QGraphicsTransformPrivate +{ +public: + QDeclarativeTranslatePrivate() + : x(0), y(0), z(0) {} + qreal x; + qreal y; + qreal z; +}; + +/*! + Constructs an empty QDeclarativeTranslate object with the given \a parent. +*/ +QDeclarativeTranslate::QDeclarativeTranslate(QObject *parent) + : QGraphicsTransform(*new QDeclarativeTranslatePrivate, parent) +{ +} + +/*! + Destroys the graphics scale. +*/ +QDeclarativeTranslate::~QDeclarativeTranslate() +{ +} + +/*! + \property QDeclarativeTranslate::x + \brief the horizontal translation. + + The translation can be any real number; the default value is 0.0. + + \sa y, z +*/ +qreal QDeclarativeTranslate::x() const +{ + Q_D(const QDeclarativeTranslate); + return d->x; +} +void QDeclarativeTranslate::setX(qreal x) +{ + Q_D(QDeclarativeTranslate); + if (d->x == x) + return; + d->x = x; + update(); + emit positionChanged(); +} + +/*! + \property QDeclarativeTranslate::y + \brief the vertical translation. + + The translation can be any real number; the default value is 0.0. + + \sa x, z +*/ +qreal QDeclarativeTranslate::y() const +{ + Q_D(const QDeclarativeTranslate); + return d->y; +} +void QDeclarativeTranslate::setY(qreal y) +{ + Q_D(QDeclarativeTranslate); + if (d->y == y) + return; + d->y = y; + update(); + emit positionChanged(); +} + +/*! + \property QDeclarativeTranslate::z + \brief the depth translation. + + The translation can be any real number; the default value is 0.0. + + \sa x, y +*/ +qreal QDeclarativeTranslate::z() const +{ + Q_D(const QDeclarativeTranslate); + return d->z; +} +void QDeclarativeTranslate::setZ(qreal z) +{ + Q_D(QDeclarativeTranslate); + if (d->z == z) + return; + d->z = z; + update(); + emit positionChanged(); +} + +/*! + \reimp +*/ +void QDeclarativeTranslate::applyTo(QMatrix4x4 *matrix) const +{ + Q_D(const QDeclarativeTranslate); + matrix->translate(d->x, d->y, d->z); +} + +/*! + \fn QDeclarativeTranslate::positionChanged() + + QDeclarativeTranslate emits this signal when its position changes. + + \sa QDeclarativeTranslate::x, QDeclarativeTranslate::y + \sa QDeclarativeTranslate::z +*/ + +//#include "moc_qdeclarativetranslate.cpp" diff --git a/src/declarative/graphicsitems/qdeclarativetranslate_p.h b/src/declarative/graphicsitems/qdeclarativetranslate_p.h new file mode 100644 index 0000000..54bfc3d --- /dev/null +++ b/src/declarative/graphicsitems/qdeclarativetranslate_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used 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. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVETRANSLATE_H +#define QDECLARATIVETRANSLATE_H + +#include "qdeclarativeitem.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeTranslatePrivate; + +class Q_GUI_EXPORT QDeclarativeTranslate : public QGraphicsTransform +{ + Q_OBJECT + + Q_PROPERTY(qreal x READ x WRITE setX NOTIFY positionChanged) + Q_PROPERTY(qreal y READ y WRITE setY NOTIFY positionChanged) + Q_PROPERTY(qreal z READ z WRITE setZ NOTIFY positionChanged) + +public: + QDeclarativeTranslate(QObject *parent = 0); + ~QDeclarativeTranslate(); + + qreal x() const; + void setX(qreal); + + qreal y() const; + void setY(qreal); + + qreal z() const; + void setZ(qreal); + + void applyTo(QMatrix4x4 *matrix) const; + +Q_SIGNALS: + void positionChanged(); + +private: + Q_DECLARE_PRIVATE(QDeclarativeTranslate) + Q_DISABLE_COPY(QDeclarativeTranslate) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeTranslate) + +QT_END_HEADER + +#endif diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp index e78fdf1..bbe86e7 100644 --- a/src/declarative/util/qdeclarativepixmapcache.cpp +++ b/src/declarative/util/qdeclarativepixmapcache.cpp @@ -106,7 +106,7 @@ public: QDeclarativeImageReader(QDeclarativeEngine *eng); ~QDeclarativeImageReader(); - QDeclarativePixmapReply *getImage(const QUrl &url); + QDeclarativePixmapReply *getImage(const QUrl &url, int req_width, int req_height); void cancel(QDeclarativePixmapReply *rep); static QDeclarativeImageReader *instance(QDeclarativeEngine *engine); @@ -140,7 +140,7 @@ public: QCoreApplication::postEvent(this, new QEvent(QEvent::User)); } - QDeclarativePixmapReply *getImage(const QUrl &url); + QDeclarativePixmapReply *getImage(const QUrl &url, int req_width, int req_height); void cancel(QDeclarativePixmapReply *reply); protected: @@ -170,11 +170,50 @@ private: //=========================================================================== +static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, int req_width, int req_height) +{ + QImageReader imgio(dev); + + bool force_scale = false; + if (url.path().endsWith(QLatin1String(".svg"),Qt::CaseInsensitive)) { + imgio.setFormat("svg"); // QSvgPlugin::capabilities bug QTBUG-9053 + force_scale = true; + } + + bool scaled = false; + if (req_width > 0 || req_height > 0) { + QSize s = imgio.size(); + if (req_width && (force_scale || req_width < s.width())) { s.setWidth(req_width); scaled = true; } + if (req_height && (force_scale || req_height < s.height())) { s.setHeight(req_height); scaled = true; } + if (scaled) { imgio.setScaledSize(s); } + } + + if (impsize) + *impsize = imgio.size(); + + if (imgio.read(image)) { + if (impsize && impsize->width() < 0) + *impsize = image->size(); + return true; + } else { + if (errorString) + *errorString = QLatin1String("Error decoding: ") + url.toString() + + QLatin1String(" \"") + imgio.errorString() + QLatin1String("\""); + return false; + } +} + + +//=========================================================================== + int QDeclarativeImageRequestHandler::replyDownloadProgress = -1; int QDeclarativeImageRequestHandler::replyFinished = -1; int QDeclarativeImageRequestHandler::downloadProgress = -1; int QDeclarativeImageRequestHandler::thisNetworkRequestDone = -1; +typedef QHash<QUrl, QSize> QDeclarativePixmapSizeHash; +Q_GLOBAL_STATIC(QDeclarativePixmapSizeHash, qmlOriginalSizes); + bool QDeclarativeImageRequestHandler::event(QEvent *event) { if (event->type() == QEvent::User) { @@ -238,10 +277,10 @@ bool QDeclarativeImageRequestHandler::event(QEvent *event) QString errorStr; QFile f(lf); if (f.open(QIODevice::ReadOnly)) { - QImageReader imgio(&f); - if (!imgio.read(&image)) { - errorStr = QLatin1String("Error decoding: ") + url.toString() - + QLatin1String(" \"") + imgio.errorString() + QLatin1String("\""); + QSize read_impsize; + if (readImage(url, &f, &image, &errorStr, &read_impsize, runningJob->forcedWidth(),runningJob->forcedHeight())) { + qmlOriginalSizes()->insert(url, read_impsize); + } else { errorCode = QDeclarativeImageReaderEvent::Loading; } } else { @@ -303,12 +342,11 @@ void QDeclarativeImageRequestHandler::networkRequestDone() error = QDeclarativeImageReaderEvent::Loading; errorString = reply->errorString(); } else { - QImageReader imgio(reply); - if (imgio.read(&image)) { + QSize read_impsize; + if (readImage(reply->url(), reply, &image, &errorString, &read_impsize, job->forcedWidth(), job->forcedHeight())) { + qmlOriginalSizes()->insert(reply->url(), read_impsize); error = QDeclarativeImageReaderEvent::NoError; } else { - errorString = QLatin1String("Error decoding: ") + reply->url().toString() - + QLatin1String(" \"") + imgio.errorString() + QLatin1String("\""); error = QDeclarativeImageReaderEvent::Decoding; } } @@ -352,10 +390,10 @@ QDeclarativeImageReader *QDeclarativeImageReader::instance(QDeclarativeEngine *e return reader; } -QDeclarativePixmapReply *QDeclarativeImageReader::getImage(const QUrl &url) +QDeclarativePixmapReply *QDeclarativeImageReader::getImage(const QUrl &url, int req_width, int req_height) { mutex.lock(); - QDeclarativePixmapReply *reply = new QDeclarativePixmapReply(this, url); + QDeclarativePixmapReply *reply = new QDeclarativePixmapReply(this, url, req_width, req_height); reply->addRef(); reply->setLoading(); jobs.append(reply); @@ -397,40 +435,6 @@ void QDeclarativeImageReader::run() //=========================================================================== -static bool readImage(QIODevice *dev, QPixmap *pixmap, QString &errorString) -{ - QImageReader imgio(dev); - -//#define QT_TEST_SCALED_SIZE -#ifdef QT_TEST_SCALED_SIZE - /* - Some mechanism is needed for loading images at a limited size, especially - for remote images. Loading only thumbnails of remote progressive JPEG - images can be efficient. (Qt jpeg handler does not do so currently) - */ - - QSize limit(60,60); - QSize sz = imgio.size(); - if (sz.width() > limit.width() || sz.height() > limit.height()) { - sz.scale(limit,Qt::KeepAspectRatio); - imgio.setScaledSize(sz); - } -#endif - - QImage img; - if (imgio.read(&img)) { -#ifdef QT_TEST_SCALED_SIZE - if (!sz.isValid()) - img = img.scaled(limit,Qt::KeepAspectRatio); -#endif - *pixmap = QPixmap::fromImage(img); - return true; - } else { - errorString = imgio.errorString(); - return false; - } -} - /*! \internal \class QDeclarativePixmapCache @@ -447,8 +451,10 @@ class QDeclarativePixmapReplyPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QDeclarativePixmapReply) public: - QDeclarativePixmapReplyPrivate(QDeclarativeImageReader *r, const QUrl &u) - : QObjectPrivate(), refCount(1), url(u), status(QDeclarativePixmapReply::Loading), loading(false), reader(r) { + QDeclarativePixmapReplyPrivate(QDeclarativeImageReader *r, const QUrl &u, int req_width, int req_height) + : QObjectPrivate(), refCount(1), url(u), status(QDeclarativePixmapReply::Loading), loading(false), reader(r), + forced_width(req_width), forced_height(req_height) + { } int refCount; @@ -457,11 +463,12 @@ public: QDeclarativePixmapReply::Status status; bool loading; QDeclarativeImageReader *reader; + int forced_width, forced_height; }; -QDeclarativePixmapReply::QDeclarativePixmapReply(QDeclarativeImageReader *reader, const QUrl &url) - : QObject(*new QDeclarativePixmapReplyPrivate(reader, url), 0) +QDeclarativePixmapReply::QDeclarativePixmapReply(QDeclarativeImageReader *reader, const QUrl &url, int req_width, int req_height) + : QObject(*new QDeclarativePixmapReplyPrivate(reader, url, req_width, req_height), 0) { } @@ -475,6 +482,28 @@ const QUrl &QDeclarativePixmapReply::url() const return d->url; } +int QDeclarativePixmapReply::forcedWidth() const +{ + Q_D(const QDeclarativePixmapReply); + return d->forced_width; +} + +int QDeclarativePixmapReply::forcedHeight() const +{ + Q_D(const QDeclarativePixmapReply); + return d->forced_height; +} + +QSize QDeclarativePixmapReply::implicitSize() const +{ + Q_D(const QDeclarativePixmapReply); + QDeclarativePixmapSizeHash::Iterator iter = qmlOriginalSizes()->find(d->url); + if (iter != qmlOriginalSizes()->end()) + return *iter; + else + return QSize(); +} + bool QDeclarativePixmapReply::event(QEvent *event) { Q_D(QDeclarativePixmapReply); @@ -554,13 +583,25 @@ bool QDeclarativePixmapReply::release(bool defer) If \a async is false the image will be loaded and decoded immediately; otherwise the image will be loaded and decoded in a separate thread. + If \a req_width and \a req_height are non-zero, they are used for + the size of the rendered pixmap rather than the intrinsic size of the image. + Different request sizes add different cache items. + Note that images sourced from the network will always be loaded and decoded asynchonously. */ -QDeclarativePixmapReply::Status QDeclarativePixmapCache::get(const QUrl& url, QPixmap *pixmap, bool async) +QDeclarativePixmapReply::Status QDeclarativePixmapCache::get(const QUrl& url, QPixmap *pixmap, QSize *impsize, bool async, int req_width, int req_height) { QDeclarativePixmapReply::Status status = QDeclarativePixmapReply::Unrequested; QByteArray key = url.toEncoded(QUrl::FormattingOption(0x100)); + + if (req_width > 0 && req_height > 0) { + key += ':'; + key += QByteArray::number(req_width); + key += 'x'; + key += QByteArray::number(req_height); + } + QString strKey = QString::fromLatin1(key.constData(), key.count()); #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML @@ -570,11 +611,13 @@ QDeclarativePixmapReply::Status QDeclarativePixmapCache::get(const QUrl& url, QP status = QDeclarativePixmapReply::Ready; if (!QPixmapCache::find(strKey,pixmap)) { QFile f(lf); + QSize read_impsize; if (f.open(QIODevice::ReadOnly)) { QString errorString; - if (!readImage(&f, pixmap, errorString)) { - errorString = QLatin1String("Error decoding: ") + url.toString() - + QLatin1String(" \"") + errorString + QLatin1String("\""); + QImage image; + if (readImage(url, &f, &image, &errorString, &read_impsize, req_width, req_height)) { + *pixmap = QPixmap::fromImage(image); + } else { qWarning() << errorString; *pixmap = QPixmap(); status = QDeclarativePixmapReply::Error; @@ -584,8 +627,18 @@ QDeclarativePixmapReply::Status QDeclarativePixmapCache::get(const QUrl& url, QP *pixmap = QPixmap(); status = QDeclarativePixmapReply::Error; } - if (status == QDeclarativePixmapReply::Ready) + if (status == QDeclarativePixmapReply::Ready) { QPixmapCache::insert(strKey, *pixmap); + qmlOriginalSizes()->insert(url, read_impsize); + } + if (impsize) + *impsize = read_impsize; + } else { + if (impsize) { + QDeclarativePixmapSizeHash::Iterator iter = qmlOriginalSizes()->find(url); + if (iter != qmlOriginalSizes()->end()) + *impsize = *iter; + } } return status; } @@ -608,6 +661,11 @@ QDeclarativePixmapReply::Status QDeclarativePixmapCache::get(const QUrl& url, QP } else if (iter != qmlActivePixmapReplies()->end()) { status = QDeclarativePixmapReply::Loading; } + if (impsize) { + QDeclarativePixmapSizeHash::Iterator iter = qmlOriginalSizes()->find(url); + if (iter != qmlOriginalSizes()->end()) + *impsize = *iter; + } return status; } @@ -621,12 +679,12 @@ QDeclarativePixmapReply::Status QDeclarativePixmapCache::get(const QUrl& url, QP The returned QDeclarativePixmapReply will be deleted when all request() calls are matched by a corresponding get() call. */ -QDeclarativePixmapReply *QDeclarativePixmapCache::request(QDeclarativeEngine *engine, const QUrl &url) +QDeclarativePixmapReply *QDeclarativePixmapCache::request(QDeclarativeEngine *engine, const QUrl &url, int req_width, int req_height) { QDeclarativePixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url); if (iter == qmlActivePixmapReplies()->end()) { QDeclarativeImageReader *reader = QDeclarativeImageReader::instance(engine); - QDeclarativePixmapReply *item = reader->getImage(url); + QDeclarativePixmapReply *item = reader->getImage(url, req_width, req_height); iter = qmlActivePixmapReplies()->insert(url, item); } else { (*iter)->addRef(); diff --git a/src/declarative/util/qdeclarativepixmapcache_p.h b/src/declarative/util/qdeclarativepixmapcache_p.h index b8949db..0ccf469 100644 --- a/src/declarative/util/qdeclarativepixmapcache_p.h +++ b/src/declarative/util/qdeclarativepixmapcache_p.h @@ -66,6 +66,9 @@ public: Status status() const; const QUrl &url() const; + int forcedWidth() const; + int forcedHeight() const; + QSize implicitSize() const; Q_SIGNALS: void finished(); @@ -81,7 +84,7 @@ private: void setLoading(); private: - QDeclarativePixmapReply(QDeclarativeImageReader *reader, const QUrl &url); + QDeclarativePixmapReply(QDeclarativeImageReader *reader, const QUrl &url, int req_width, int req_height); Q_DISABLE_COPY(QDeclarativePixmapReply) Q_DECLARE_PRIVATE(QDeclarativePixmapReply) friend class QDeclarativeImageRequestHandler; @@ -92,8 +95,8 @@ private: class Q_DECLARATIVE_EXPORT QDeclarativePixmapCache { public: - static QDeclarativePixmapReply::Status get(const QUrl& url, QPixmap *pixmap, bool async=false); - static QDeclarativePixmapReply *request(QDeclarativeEngine *, const QUrl& url); + static QDeclarativePixmapReply::Status get(const QUrl& url, QPixmap *pixmap, QSize *impsize, bool async=false, int req_width=0, int req_height=0); + static QDeclarativePixmapReply *request(QDeclarativeEngine *, const QUrl& url, int req_width=0, int req_height=0); static void cancel(const QUrl& url, QObject *obj); static int pendingRequests(); }; |