← Back to team overview

ubuntu-touch-coreapps-reviewers team mailing list archive

[Merge] lp:~mrqtros/ubuntu-docviewer-app/ubuntu-docviewer-app-cppoptimizations into lp:ubuntu-docviewer-app

 

Roman Shchekin has proposed merging lp:~mrqtros/ubuntu-docviewer-app/ubuntu-docviewer-app-cppoptimizations into lp:ubuntu-docviewer-app.

Commit message:
Code cleanup - phase 2.

Requested reviews:
  Ubuntu Document Viewer Developers (ubuntu-docviewer-dev)

For more details, see:
https://code.launchpad.net/~mrqtros/ubuntu-docviewer-app/ubuntu-docviewer-app-cppoptimizations/+merge/278899

A lot of C++ code impovements:
 * Some code was reorganaized (AbstractTaskEngine)
 * RenderEngine API was changed
 * More staff

Nothing new, but code now is easy to maintain.
 
-- 
Your team Ubuntu Document Viewer Developers is requested to review the proposed merge of lp:~mrqtros/ubuntu-docviewer-app/ubuntu-docviewer-app-cppoptimizations into lp:ubuntu-docviewer-app.
=== modified file 'po/com.ubuntu.docviewer.pot'
--- po/com.ubuntu.docviewer.pot	2015-11-28 11:31:03 +0000
+++ po/com.ubuntu.docviewer.pot	2015-11-28 22:30:06 +0000
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-11-27 17:38+0100\n"
+"POT-Creation-Date: 2015-11-29 01:09+0300\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@xxxxxx>\n"
@@ -42,7 +42,7 @@
 msgstr ""
 
 #: ../src/app/qml/common/DetailsPage.qml:25
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:107
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:108
 #: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:83
 #: ../src/app/qml/textView/TextViewDefaultHeader.qml:69
 msgid "Details"
@@ -166,12 +166,12 @@
 msgstr[1] ""
 
 #: ../src/app/qml/documentPage/DeleteFileDialog.qml:61
-#: ../src/app/qml/documentPage/DocumentDelegateActions.qml:27
+#: ../src/app/qml/documentPage/DocumentDelegateActions.qml:25
 #: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:53
 msgid "Delete"
 msgstr ""
 
-#: ../src/app/qml/documentPage/DocumentDelegateActions.qml:46
+#: ../src/app/qml/documentPage/DocumentDelegateActions.qml:44
 msgid "Share"
 msgstr ""
 
@@ -187,28 +187,28 @@
 
 #. TRANSLATORS: %1 refers to a time formatted as Locale.ShortFormat (e.g. hh:mm). It depends on system settings.
 #. http://qt-project.org/doc/qt-4.8/qlocale.html#FormatType-enum
-#: ../src/app/qml/documentPage/DocumentListDelegate.qml:95
+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:100
 #, qt-format
 msgid "Today, %1"
 msgstr ""
 
 #. TRANSLATORS: %1 refers to a time formatted as Locale.ShortFormat (e.g. hh:mm). It depends on system settings.
 #. http://qt-project.org/doc/qt-4.8/qlocale.html#FormatType-enum
-#: ../src/app/qml/documentPage/DocumentListDelegate.qml:100
+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:105
 #, qt-format
 msgid "Yesterday, %1"
 msgstr ""
 
 #. TRANSLATORS: this is a datetime formatting string,
 #. see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
-#: ../src/app/qml/documentPage/DocumentListDelegate.qml:107
-#: ../src/app/qml/documentPage/DocumentListDelegate.qml:126
+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:112
+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:131
 msgid "yyyy/MM/dd hh:mm"
 msgstr ""
 
 #. TRANSLATORS: this is a datetime formatting string,
 #. see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
-#: ../src/app/qml/documentPage/DocumentListDelegate.qml:120
+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:125
 msgid "dddd, hh:mm"
 msgstr ""
 
@@ -334,17 +334,17 @@
 msgid "Unknown type document"
 msgstr ""
 
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:94
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:95
 msgid "Go to position..."
 msgstr ""
 
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:101
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:102
 #: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:77
 #: ../src/app/qml/textView/TextViewDefaultHeader.qml:63
 msgid "Disable night mode"
 msgstr ""
 
-#: ../src/app/qml/loView/LOViewDefaultHeader.qml:101
+#: ../src/app/qml/loView/LOViewDefaultHeader.qml:102
 #: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:77
 #: ../src/app/qml/textView/TextViewDefaultHeader.qml:63
 msgid "Enable night mode"
@@ -363,15 +363,15 @@
 msgid "GO!"
 msgstr ""
 
-#: ../src/app/qml/loView/LOViewPage.qml:175
+#: ../src/app/qml/loView/LOViewPage.qml:149
 msgid "LibreOffice binaries not found."
 msgstr ""
 
-#: ../src/app/qml/loView/LOViewPage.qml:178
+#: ../src/app/qml/loView/LOViewPage.qml:152
 msgid "Error while loading LibreOffice."
 msgstr ""
 
-#: ../src/app/qml/loView/LOViewPage.qml:181
+#: ../src/app/qml/loView/LOViewPage.qml:155
 msgid ""
 "Document not loaded.\n"
 "The requested document may be corrupt."
@@ -429,10 +429,10 @@
 msgid "copy %1"
 msgstr ""
 
-#: /tmp/build-reboot-uitk13-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
+#: /home/qtros/dev/ubuntu-docviewer-app-cpp-optimizations-build/po/com.ubuntu.docviewer.desktop.in.in.h:1
 msgid "Document Viewer"
 msgstr ""
 
-#: /tmp/build-reboot-uitk13-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
+#: /home/qtros/dev/ubuntu-docviewer-app-cpp-optimizations-build/po/com.ubuntu.docviewer.desktop.in.in.h:2
 msgid "documents;viewer;pdf;reader;"
 msgstr ""

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/config.h'
--- src/plugin/libreofficetoolkit-qml-plugin/config.h	2015-11-18 12:50:27 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/config.h	2015-11-28 22:30:06 +0000
@@ -66,7 +66,7 @@
         if (loPath.isEmpty()) {
             qDebug() << "LibreOffice binaries not found.";
 
-            return NULL;
+            return nullptr;
         }
 
         else {

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp	2015-11-11 19:59:15 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lodocument.cpp	2015-11-28 22:30:06 +0000
@@ -36,7 +36,7 @@
   : m_path("")
   , m_currentPart(-1)
   , m_error(LibreOfficeError::NoError)
-  , m_document(nullptr)
+  , m_lokDocument(nullptr)
 {
     // This space is intentionally empty.
 }
@@ -66,7 +66,7 @@
 
 void LODocument::setCurrentPart(int index)
 {
-    if (!m_document)
+    if (!m_lokDocument)
         return;
 
     if (m_currentPart == index || index < 0 || index > partsCount() - 1)
@@ -91,7 +91,7 @@
     /* Get LibreOffice path */
     const char* loPath = Config::getLibreOfficePath();
 
-    if (loPath == NULL) {
+    if (!loPath) {
         setError(LibreOfficeError::LibreOfficeNotFound);
         return;
     }
@@ -101,7 +101,7 @@
     if (!s_office)
         s_office = lok::lok_cpp_init(loPath, Config::getLibreOfficeProfilePath());
 
-    if (s_office == NULL) {
+    if (!s_office) {
         setError(LibreOfficeError::LibreOfficeNotInitialized);
         qDebug() << "[lok-qml]: LibreOffice not initialized.";
         return;
@@ -109,9 +109,9 @@
 
 
     /* Load the document */
-    m_document = s_office->documentLoad(m_path.toUtf8().constData());
+    m_lokDocument = s_office->documentLoad(m_path.toUtf8().constData());
 
-    if (m_document == NULL) {
+    if (!m_lokDocument) {
         setError(LibreOfficeError::DocumentNotLoaded);
         qDebug() << "[lok-qml]: Document not loaded.";
         return;
@@ -119,12 +119,12 @@
 
 
     /* Do the further initialization */
-    m_docType = DocumentType(m_document->getDocumentType());
+    m_docType = DocumentType(m_lokDocument->getDocumentType());
     Q_EMIT documentTypeChanged();
 
-    setCurrentPart(m_document->getPart());
+    setCurrentPart(m_lokDocument->getPart());
 
-    m_document->initializeForRendering();
+    m_lokDocument->initializeForRendering();
     qDebug() << "Document loaded successfully !";
 
     return;
@@ -148,31 +148,31 @@
 
 int LODocument::documentPart() const
 {
-    return m_document->getPart();
+    return m_lokDocument->getPart();
 }
 
 void LODocument::setDocumentPart(int p)
 {
     if (documentPart() != p)
-        m_document->setPart(p);
+        m_lokDocument->setPart(p);
 }
 
 // Return the size of the document, in TWIPs
 QSize LODocument::documentSize() const
 {
-    if (!m_document)
+    if (!m_lokDocument)
         return QSize(0, 0);
 
     long pWidth(0);
     long pHeight(0);
-    m_document->getDocumentSize(&pWidth, &pHeight);
+    m_lokDocument->getDocumentSize(&pWidth, &pHeight);
 
     return QSize(pWidth, pHeight);
 }
 
 QImage LODocument::paintTile(const QSize& canvasSize, const QRect& tileSize, const qreal &zoom)
 {
-    if (!m_document)
+    if (!m_lokDocument)
         return QImage();
 
     QImage result = QImage(canvasSize.width(), canvasSize.height(),  QImage::Format_RGB32);
@@ -182,7 +182,7 @@
     renderTimer.start();
 #endif
 
-    m_document->paintTile(result.bits(),
+    m_lokDocument->paintTile(result.bits(),
                           canvasSize.width(), canvasSize.height(),
                           Twips::convertPixelsToTwips(tileSize.x(), zoom),
                           Twips::convertPixelsToTwips(tileSize.y(), zoom),
@@ -198,7 +198,7 @@
 
 QImage LODocument::paintThumbnail(qreal size)
 {
-    if (!m_document)
+    if (!m_lokDocument)
         return QImage();
 
 #ifdef DEBUG_TILE_BENCHMARK
@@ -220,7 +220,7 @@
     }
 
     QImage result = QImage(resultSize.width(), resultSize.height(), QImage::Format_RGB32);
-    m_document->paintTile(result.bits(), resultSize.width(), resultSize.height(),
+    m_lokDocument->paintTile(result.bits(), resultSize.width(), resultSize.height(),
                           0, 0, tWidth, tHeight);
 
 #ifdef DEBUG_TILE_BENCHMARK
@@ -232,18 +232,18 @@
 
 int LODocument::partsCount()
 {
-    if (!m_document)
+    if (!m_lokDocument)
         return int(0);
  
-    return m_document->getParts();
+    return m_lokDocument->getParts();
 }
  
 QString LODocument::getPartName(int index) const
 {
-    if (!m_document)
+    if (!m_lokDocument)
         return QString();
  
-    return QString::fromUtf8(m_document->getPartName(index));
+    return QString::fromUtf8(m_lokDocument->getPartName(index));
 }
 
 LibreOfficeError::Error LODocument::error() const
@@ -255,19 +255,19 @@
 // be used?
 bool LODocument::saveAs(QString url, QString format = QString(), QString filterOptions = QString())
 {
-    if (!m_document) {
+    if (!m_lokDocument) {
         qDebug() << "No loaded document. It's not possible to save this file.";
         return false;
     }
 
-    return m_document->saveAs(url.toLatin1().constData(),
+    return m_lokDocument->saveAs(url.toLatin1().constData(),
                               format.toLatin1().constData(),
                               filterOptions.toLatin1().constData());
 }
 
 LODocument::~LODocument()
 {
-    delete m_document;
+    delete m_lokDocument;
 #ifdef DEBUG_VERBOSE
     qDebug() << " ---- ~LODocument";
 #endif

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lodocument.h'
--- src/plugin/libreofficetoolkit-qml-plugin/lodocument.h	2015-11-11 19:59:15 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lodocument.h	2015-11-28 22:30:06 +0000
@@ -71,8 +71,6 @@
 
     int partsCount();
     QString getPartName(int index) const;
-    void setPart(int index);
-
     LibreOfficeError::Error error() const;
 
     Q_INVOKABLE bool saveAs(QString url, QString format, QString filterOptions);
@@ -89,14 +87,13 @@
     int m_currentPart;
     DocumentType m_docType;
     LibreOfficeError::Error m_error;
+    lok::Document *m_lokDocument;
+    static lok::Office *s_office;
 
+private:
     void loadDocument(const QString &pathNAme);
-
     void setError(const LibreOfficeError::Error &error);
 
-    lok::Document *m_document;
-
-    static lok::Office *s_office;
 };
 
 #endif // LODOCUMENT_H

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp	2015-10-18 21:27:16 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.cpp	2015-11-28 22:30:06 +0000
@@ -43,7 +43,7 @@
 
     const int defaultSize = 256;
 
-    RenderEngine::instance()->enqueueThumbnailTask(m_document, partNumber, defaultSize, itemId);
+    RenderEngine::instance()->enqueueTask(createTask(partNumber, defaultSize, itemId));
 
     // Return default image (empty).
     static QImage defaultImage;
@@ -52,3 +52,13 @@
 
     return defaultImage;
 }
+
+ThumbnailRenderTask *LOPartsImageProvider::createTask(int part, qreal size, int id) const
+{
+    ThumbnailRenderTask* task = new ThumbnailRenderTask();
+    task->setId(id);
+    task->setPart(part);
+    task->setDocument(m_document);
+    task->setSize(size);
+    return task;
+}

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.h'
--- src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.h	2015-10-05 22:27:07 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lopartsimageprovider.h	2015-11-28 22:30:06 +0000
@@ -23,6 +23,8 @@
 #include <QHash>
 #include <QDebug>
 
+#include "rendertask.h"
+
 class LODocument;
 
 class LOPartsImageProvider : public QQuickImageProvider
@@ -35,6 +37,9 @@
 
 private:
     QSharedPointer<LODocument> m_document;
+
+private:
+    ThumbnailRenderTask* createTask(int part, qreal size, int id) const;
 };
 
 #endif // LOPARTSIMAGEPROVIDER_H

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.h'
--- src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.h	2015-10-11 11:27:29 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/lopartsmodel.h	2015-11-28 22:30:06 +0000
@@ -30,14 +30,13 @@
 {
 public:
     LOPartEntry():
+        id(0),
         index(0)
-    {
-        id = RenderEngine::getNextId();
-    }
+    { }
 
     int id;
+    int index;
     QString name;
-    int index;
     QString thumbnail;
 };
 

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/loview.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/loview.cpp	2015-11-22 13:33:50 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/loview.cpp	2015-11-28 22:30:06 +0000
@@ -50,10 +50,8 @@
     connect(this, SIGNAL(cacheBufferChanged()), this, SLOT(updateVisibleRect()));
     connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateVisibleRect()));
 
-    connect(RenderEngine::instance(), SIGNAL(tileRenderFinished(int,QImage)),
-            this, SLOT(slotTileRenderFinished(int,QImage)));
-    connect(RenderEngine::instance(), SIGNAL(thumbnailRenderFinished(int,QImage)),
-            this, SLOT(slotThumbnailRenderFinished(int,QImage)));
+    connect(RenderEngine::instance(), &RenderEngine::taskRenderFinished,
+            this, &LOView::slotTaskRenderFinished);
 }
 
 // Returns the parent QML Flickable
@@ -346,7 +344,16 @@
     updateViewSize();
 }
 
-void LOView::createTile(int index, QRect rect)
+void LOView::slotTaskRenderFinished(AbstractRenderTask* task, QImage img)
+{
+    if (task->type() == RttTile) {
+        updateTileData(task, img);
+    } else if (task->type() == RttImpressThumbnail) {
+        updateThumbnailModel(task, img);
+    }
+}
+
+void LOView::createTile(int index, const QRect &rect)
 {
     if (!m_tiles.contains(index)) {
 #ifdef DEBUG_VERBOSE
@@ -355,7 +362,7 @@
 
         auto tile = new SGTileItem(rect, m_zoomFactor, RenderEngine::getNextId(), this);
         m_tiles.insert(index, tile);
-        RenderEngine::instance()->enqueueTileTask(m_document, m_document->currentPart(), rect, m_zoomFactor, tile->id());
+        RenderEngine::instance()->enqueueTask(createTask(rect, tile->id()));
     }
 #ifdef DEBUG_VERBOSE
     else {
@@ -373,8 +380,35 @@
     m_updateTimer.start(20);
 }
 
-void LOView::slotTileRenderFinished(int id, QImage img)
-{
+
+
+void LOView::clearView()
+{
+    for (auto i = m_tiles.begin(); i != m_tiles.end(); ++i)
+        RenderEngine::instance()->dequeueTask(i.value()->id());
+
+    auto i = m_tiles.begin();
+    while (i != m_tiles.end()) {
+        SGTileItem* sgtile = i.value();
+        sgtile->deleteLater();
+        i = m_tiles.erase(i);
+    }
+}
+
+TileRenderTask* LOView::createTask(const QRect &rect, int id) const
+{
+    TileRenderTask* task = new TileRenderTask();
+    task->setId(id);
+    task->setPart(m_document->currentPart());
+    task->setDocument(m_document);
+    task->setArea(rect);
+    task->setZoom(m_zoomFactor);
+    return task;
+}
+
+void LOView::updateTileData(AbstractRenderTask* task, QImage img)
+{
+    int id = task->id();
     for (auto i = m_tiles.begin(); i != m_tiles.end(); ++i) {
         SGTileItem* sgtile = i.value();
         if (sgtile->id() == id) {
@@ -384,26 +418,14 @@
     }
 }
 
-void LOView::slotThumbnailRenderFinished(int id, QImage img)
+void LOView::updateThumbnailModel(AbstractRenderTask* task, QImage img)
 {
+    int id = task->id();
     if (!m_imageProvider->m_images.contains(id))
         m_imageProvider->m_images.insert(id, img);
     m_partsModel->notifyAboutChanges(id);
 }
 
-void LOView::clearView()
-{
-    for (auto i = m_tiles.begin(); i != m_tiles.end(); ++i)
-        RenderEngine::instance()->dequeueTask(i.value()->id());
-
-    auto i = m_tiles.begin();
-    while (i != m_tiles.end()) {
-        SGTileItem* sgtile = i.value();
-        sgtile->deleteLater();
-        i = m_tiles.erase(i);
-    }
-}
-
 void LOView::setError(const LibreOfficeError::Error &error)
 {
     if (m_error == error)
@@ -417,10 +439,8 @@
 {
     delete m_partsModel;
 
-    disconnect(RenderEngine::instance(), SIGNAL(tileRenderFinished(int,QImage)),
-               this, SLOT(slotTileRenderFinished(int,QImage)));
-    disconnect(RenderEngine::instance(), SIGNAL(thumbnailRenderFinished(int,QImage)),
-               this, SLOT(slotThumbnailRenderFinished(int,QImage)));
+    disconnect(RenderEngine::instance(), &RenderEngine::taskRenderFinished,
+            this, &LOView::slotTaskRenderFinished);
 
     // Remove all tasks from rendering queue.
     for (auto i = m_tiles.begin(); i != m_tiles.end(); ++i)

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/loview.h'
--- src/plugin/libreofficetoolkit-qml-plugin/loview.h	2015-11-22 13:33:50 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/loview.h	2015-11-28 22:30:06 +0000
@@ -24,6 +24,7 @@
 #include <QQmlEngine>
 
 #include "loerror.h"
+#include "rendertask.h"
 #include "renderengine.h"
 #include "lopartsmodel.h"
 #include "lopartsimageprovider.h"
@@ -86,9 +87,7 @@
     void updateVisibleRect();
     void scheduleVisibleRectUpdate();
     void invalidateAllTiles();
-
-    void slotTileRenderFinished(int id, QImage img);
-    void slotThumbnailRenderFinished(int id, QImage img);
+    void slotTaskRenderFinished(AbstractRenderTask* task, QImage img);
 
 private:
 
@@ -111,9 +110,12 @@
     QMap<int, SGTileItem*>      m_tiles;
 
     void generateTiles(int x1, int y1, int x2, int y2, int tilesPerWidth, int tilesPerHeight);
-    void createTile(int index, QRect rect);
+    void createTile(int index, const QRect& rect);
     void setZoomMode(const ZoomMode zoomMode);
     void clearView();
+    TileRenderTask* createTask(const QRect& rect, int id) const;
+    void updateTileData(AbstractRenderTask* task, QImage img);
+    void updateThumbnailModel(AbstractRenderTask* task, QImage img);
 
     void setError(const LibreOfficeError::Error &error);
 };

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp	2015-10-31 20:37:19 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/renderengine.cpp	2015-11-28 22:30:06 +0000
@@ -16,33 +16,6 @@
     qRegisterMetaType<AbstractRenderTask*>();
 }
 
-void RenderEngine::enqueueTileTask(const QSharedPointer<LODocument>& doc, int part, const QRect& area, qreal zoom, int id)
-{
-    Q_ASSERT(doc != nullptr);
-
-    TileRenderTask* task = new TileRenderTask();
-    task->setId(id);
-    task->setPart(part);
-    task->setDocument(doc);
-    task->setArea(area);
-    task->setZoom(zoom);
-
-    enqueueTask(task);
-}
-
-void RenderEngine::enqueueThumbnailTask(const QSharedPointer<LODocument> &doc, int part, qreal size, int id)
-{
-    Q_ASSERT(doc != nullptr);
-
-    ThumbnailRenderTask* task = new ThumbnailRenderTask();
-    task->setId(id);
-    task->setPart(part);
-    task->setDocument(doc);
-    task->setSize(size);
-
-    enqueueTask(task);
-}
-
 void RenderEngine::enqueueTask(AbstractRenderTask *task)
 {
     m_queue.enqueue(task);
@@ -70,22 +43,10 @@
         doDispose();
     }
 
-    switch (task->type())
-    {
-    case RttTile:
-        Q_EMIT tileRenderFinished(task->id(), img);
-        break;
-    case RttImpressThumbnail:
-        Q_EMIT thumbnailRenderFinished(task->id(), img);
-        break;
-    case RttPdfPage:
-    case RttUnknown:
-    default:
-        break;
-    }
+    // Notify about result.
+    emit taskRenderFinished(task, img);
 
     doNextTask();
-
     disposeLater(task);
 }
 

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/renderengine.h'
--- src/plugin/libreofficetoolkit-qml-plugin/renderengine.h	2015-10-31 20:37:19 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/renderengine.h	2015-11-28 22:30:06 +0000
@@ -23,9 +23,7 @@
     const int DefaultIdealThreadCount = 2;
 
 public:
-    void enqueueTileTask(const QSharedPointer<LODocument>& doc, int part, const QRect& area, qreal zoom, int id);
-    void enqueueThumbnailTask(const QSharedPointer<LODocument>& doc, int part, qreal size, int id);
-    void enqueueTask(AbstractRenderTask* task);
+    void enqueueTask(AbstractRenderTask* task);     // Takes ownership.
     void dequeueTask(int id);
 
     static RenderEngine* instance() {
@@ -40,9 +38,7 @@
     }
 
 Q_SIGNALS:
-    void tileRenderFinished(int id, QImage img);
-    void thumbnailRenderFinished(int id, QImage img);
-    void enabledChanged();
+    void taskRenderFinished(AbstractRenderTask* task, QImage img);
 
 private:
     Q_INVOKABLE void internalRenderCallback(AbstractRenderTask* task, QImage img);

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/rendertask.cpp'
--- src/plugin/libreofficetoolkit-qml-plugin/rendertask.cpp	2015-10-18 20:58:32 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/rendertask.cpp	2015-11-28 22:30:06 +0000
@@ -1,1 +1,25 @@
 #include "rendertask.h"
+
+bool LoRenderTask::canBeRunInParallel(AbstractRenderTask* prevTask)
+{
+    Q_ASSERT(prevTask != nullptr);
+    if (prevTask->type() == RttTile || prevTask->type() == RttImpressThumbnail) {
+        LoRenderTask* loTask = static_cast<LoRenderTask*>(prevTask);
+
+        // Another document or the same part in the same document can be run parallel.
+        return (loTask->document() != m_document ||
+                loTask->part() == m_part);
+    }
+
+    return true;
+}
+
+QImage TileRenderTask::doWork()
+{
+    return m_document->paintTile(m_area.size(), m_area, m_zoom);
+}
+
+QImage ThumbnailRenderTask::doWork()
+{
+    return m_document->paintThumbnail(m_size);
+}

=== modified file 'src/plugin/libreofficetoolkit-qml-plugin/rendertask.h'
--- src/plugin/libreofficetoolkit-qml-plugin/rendertask.h	2015-10-31 20:37:19 +0000
+++ src/plugin/libreofficetoolkit-qml-plugin/rendertask.h	2015-11-28 22:30:06 +0000
@@ -10,17 +10,19 @@
 
 #include "lodocument.h"
 
+/* Required for super-fast type detection.
+ * NOTE: only leaf nodes in inheritance tree have correct types.
+ */
 enum RenderTaskType
 {
     RttUnknown = 0x0,
     RttTile = 0x1,
     RttImpressThumbnail = 0x2,
-    RttPdfPage = 0x3 // TODO
+    RttPdfPage = 0x3
 };
 
 class AbstractRenderTask
 {
-
 public:
     virtual RenderTaskType type() { return RttUnknown; }
     virtual QImage doWork() = 0 ;
@@ -39,25 +41,11 @@
 class LoRenderTask : public AbstractRenderTask
 {
 public:
-    virtual bool canBeRunInParallel(AbstractRenderTask* prevTask)
-    {
-        Q_ASSERT(prevTask != nullptr);
-        if (prevTask->type() == RttTile || prevTask->type() == RttImpressThumbnail) {
-            LoRenderTask* loTask = static_cast<LoRenderTask*>(prevTask);
-
-            // Another document or the same part in the same document can be run parallel.
-            return (loTask->document() != m_document ||
-                    loTask->part() == m_part);
-        }
-
-        return true;
-    }
-
+    virtual bool canBeRunInParallel(AbstractRenderTask* prevTask);
     virtual void prepare() { m_document->setDocumentPart(m_part); }
 
     int part() { return m_part; }
     void setPart(int p) { m_part = p; }
-
     QSharedPointer<LODocument> document() { return m_document; }
     void setDocument(QSharedPointer<LODocument> d) { m_document = d; }
 protected:
@@ -69,10 +57,8 @@
 {
 public:
     virtual RenderTaskType type() { return RttTile; }
-    virtual QImage doWork()
-    {
-        return m_document->paintTile(m_area.size(), m_area, m_zoom);
-    }
+    virtual QImage doWork();
+
     QRect area() { return m_area; }
     void setArea(const QRect& a) { m_area = a; }
     qreal zoom() { return m_zoom; }
@@ -86,10 +72,8 @@
 {
 public:
     virtual RenderTaskType type() { return RttImpressThumbnail; }
-    virtual QImage doWork()
-    {
-        return m_document->paintThumbnail(m_size);
-    }
+    virtual QImage doWork();
+
     qreal size() { return m_size; }
     void setSize(qreal s) { m_size = s; }
 protected:


Follow ups