diff --git a/src/gui/image/qicon_p.h b/src/gui/image/qicon_p.h
index e0fec112b5d927347901a7f59a20352b0c6182fa..8b42e770fac9b205094554830fc6b2f20e9c5f6b 100644
--- a/src/gui/image/qicon_p.h
+++ b/src/gui/image/qicon_p.h
@@ -99,7 +99,7 @@ inline QPixmapIconEngineEntry::QPixmapIconEngineEntry(const QString &file, const
     pixmap.setDevicePixelRatio(1.0);
 }
 
-class QPixmapIconEngine : public QIconEngine {
+class Q_GUI_EXPORT QPixmapIconEngine : public QIconEngine {
 public:
     QPixmapIconEngine();
     QPixmapIconEngine(const QPixmapIconEngine &);
diff --git a/src/widgets/itemviews/qfileiconprovider.cpp b/src/widgets/itemviews/qfileiconprovider.cpp
index d1bd0e657e9369f789c04e1bc98e66d5fef57ed1..740bd853b7a63237ff4b90c66554110492e5db90 100644
--- a/src/widgets/itemviews/qfileiconprovider.cpp
+++ b/src/widgets/itemviews/qfileiconprovider.cpp
@@ -39,6 +39,7 @@
 #include <qpixmapcache.h>
 #include <private/qfunctions_p.h>
 #include <private/qguiapplication_p.h>
+#include <private/qicon_p.h>
 #include <qpa/qplatformintegration.h>
 #include <qpa/qplatformservices.h>
 #include <qpa/qplatformtheme.h>
@@ -57,6 +58,88 @@
 
 QT_BEGIN_NAMESPACE
 
+static bool isCacheable(const QFileInfo &fi);
+
+class QFileIconEngine : public QPixmapIconEngine
+{
+public:
+    QFileIconEngine(const QFileIconProvider *fip, const QFileInfo &info)
+        : QPixmapIconEngine(), m_fileIconProvider(fip), m_fileInfo(info)
+    { }
+
+    QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE
+    {
+        Q_UNUSED(mode);
+        Q_UNUSED(state);
+        QPixmap pixmap;
+
+        if (!size.isValid())
+            return pixmap;
+
+        const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
+        if (!theme)
+            return pixmap;
+
+        const QString &keyBase = QLatin1String("qt_.") + m_fileInfo.suffix().toUpper();
+
+        bool cacheable = isCacheable(m_fileInfo);
+        if (cacheable) {
+            QPixmapCache::find(keyBase + QString::number(size.width()), pixmap);
+            if (!pixmap.isNull())
+                return pixmap;
+        }
+
+        QPlatformTheme::IconOptions iconOptions;
+        if (m_fileIconProvider->options() & QFileIconProvider::DontUseCustomDirectoryIcons)
+            iconOptions |= QPlatformTheme::DontUseCustomDirectoryIcons;
+
+        pixmap = theme->fileIconPixmap(m_fileInfo, size, iconOptions);
+        if (!pixmap.isNull()) {
+            if (cacheable)
+                QPixmapCache::insert(keyBase + QString::number(size.width()), pixmap);
+        }
+
+        return pixmap;
+    }
+
+    QList<QSize> availableSizes(QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off) const Q_DECL_OVERRIDE
+    {
+        Q_UNUSED(mode);
+        Q_UNUSED(state);
+        static QList<QSize> sizes;
+        static QPlatformTheme *theme = 0;
+        if (!theme) {
+            theme = QGuiApplicationPrivate::platformTheme();
+            if (!theme)
+                return sizes;
+
+            QList<int> themeSizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<int> >();
+            if (themeSizes.isEmpty())
+                return sizes;
+
+            foreach (int size, themeSizes)
+                sizes << QSize(size, size);
+        }
+        return sizes;
+    }
+
+    QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE
+    {
+        const QList<QSize> &sizes = availableSizes(mode, state);
+        foreach (const QSize &availableSize, sizes) {
+            if (availableSize.width() >= size.width())
+                return availableSize;
+        }
+
+        return sizes.last();
+    }
+
+private:
+    const QFileIconProvider *m_fileIconProvider;
+    QFileInfo m_fileInfo;
+};
+
+
 /*!
   \class QFileIconProvider
 
@@ -86,8 +169,8 @@ QT_BEGIN_NAMESPACE
     cause a big performance impact over network or removable drives.
 */
 
-QFileIconProviderPrivate::QFileIconProviderPrivate() :
-    homePath(QDir::home().absolutePath())
+QFileIconProviderPrivate::QFileIconProviderPrivate(QFileIconProvider *q) :
+    q_ptr(q), homePath(QDir::home().absolutePath())
 {
 }
 
@@ -153,7 +236,7 @@ QIcon QFileIconProviderPrivate::getIcon(QStyle::StandardPixmap name) const
 */
 
 QFileIconProvider::QFileIconProvider()
-    : d_ptr(new QFileIconProviderPrivate)
+    : d_ptr(new QFileIconProviderPrivate(this))
 {
 }
 
@@ -238,53 +321,10 @@ static bool isCacheable(const QFileInfo &fi)
 
 QIcon QFileIconProviderPrivate::getIcon(const QFileInfo &fi) const
 {
-    QIcon retIcon;
-    const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
-    if (!theme)
-        return retIcon;
-
-    QList<int> sizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<int> >();
-    if (sizes.isEmpty())
-        return retIcon;
-
-    const QString keyBase = QLatin1String("qt_.") + fi.suffix().toUpper();
-
-    bool cacheable = isCacheable(fi);
-    if (cacheable) {
-        QPixmap pixmap;
-        QPixmapCache::find(keyBase + QString::number(sizes.at(0)), pixmap);
-        if (!pixmap.isNull()) {
-            bool iconIsComplete = true;
-            retIcon.addPixmap(pixmap);
-            for (int i = 1; i < sizes.count(); i++)
-                if (QPixmapCache::find(keyBase + QString::number(sizes.at(i)), pixmap)) {
-                    retIcon.addPixmap(pixmap);
-                } else {
-                    iconIsComplete = false;
-                    break;
-                }
-            if (iconIsComplete)
-                return retIcon;
-        }
-    }
-
-    QPlatformTheme::IconOptions iconOptions;
-    if (options & QFileIconProvider::DontUseCustomDirectoryIcons)
-        iconOptions |= QPlatformTheme::DontUseCustomDirectoryIcons;
-
-    Q_FOREACH (int size, sizes) {
-        QPixmap pixmap = theme->fileIconPixmap(fi, QSizeF(size, size), iconOptions);
-        if (!pixmap.isNull()) {
-            retIcon.addPixmap(pixmap);
-            if (cacheable)
-                QPixmapCache::insert(keyBase + QString::number(size), pixmap);
-        }
-    }
-
-    return retIcon;
+    Q_Q(const QFileIconProvider);
+    return QIcon(new QFileIconEngine(q, fi));
 }
 
-
 /*!
   Returns an icon for the file described by \a info.
 */
diff --git a/src/widgets/itemviews/qfileiconprovider_p.h b/src/widgets/itemviews/qfileiconprovider_p.h
index 213535616ce083ac4f73516c01f97a0bb44e70a4..a1fb4acbea773f13fc679bcd85e459ed19bcd60b 100644
--- a/src/widgets/itemviews/qfileiconprovider_p.h
+++ b/src/widgets/itemviews/qfileiconprovider_p.h
@@ -60,7 +60,7 @@ class QFileIconProviderPrivate
     Q_DECLARE_PUBLIC(QFileIconProvider)
 
 public:
-    QFileIconProviderPrivate();
+    QFileIconProviderPrivate(QFileIconProvider *q);
     QIcon getIcon(QStyle::StandardPixmap name) const;
     QIcon getIcon(const QFileInfo &fi) const;