File HiDPI-support.patch of Package okular

From ecc1141e0293e1a30e0f8787d86dcc6309ffb0c0 Mon Sep 17 00:00:00 2001
From: Lukas Hetzenecker <lukas@hetzenecker.me>
Date: Sat, 14 Oct 2017 14:47:20 +0200
Subject: HiDPI Support for Okular

Summary:
This patch enables HiDPI throughout the application

Every pixmap is multiplied by the devicePixelRatioF
QPainter code is ajusted to take the DPR value into account

All pixmaps get cached with the highest DPR of all screens. When moving the application to another screen, the cache doesn't have to be invalidated.

BUGS: 362856 383589
REVIEW: D6268
---
 conf/widgetconfigurationtoolsbase.cpp              |   2 +-
 core/document.cpp                                  |   4 +-
 core/generator.cpp                                 |   5 +-
 shell/main.cpp                                     |   3 +-
 ui/data/CMakeLists.txt                             |   5 +
 ui/data/tool-base-okular@2x.png                    | Bin 0 -> 2342 bytes
 ui/data/tool-highlighter-okular-colorizable@2x.png | Bin 0 -> 5188 bytes
 ui/data/tool-ink-okular-colorizable@2x.png         | Bin 0 -> 3744 bytes
 ui/data/tool-note-inline-okular-colorizable@2x.png | Bin 0 -> 945 bytes
 ui/data/tool-note-okular-colorizable@2x.png        | Bin 0 -> 1524 bytes
 ui/pagepainter.cpp                                 | 191 +++++++++++----------
 ui/pagepainter.h                                   |   6 -
 ui/pageview.cpp                                    |  14 +-
 ui/pageview.h                                      |   1 +
 ui/pageviewannotator.cpp                           |  19 +-
 ui/presentationwidget.cpp                          |  49 ++++--
 16 files changed, 168 insertions(+), 131 deletions(-)
 create mode 100644 ui/data/tool-base-okular@2x.png
 create mode 100644 ui/data/tool-highlighter-okular-colorizable@2x.png
 create mode 100644 ui/data/tool-ink-okular-colorizable@2x.png
 create mode 100644 ui/data/tool-note-inline-okular-colorizable@2x.png
 create mode 100644 ui/data/tool-note-okular-colorizable@2x.png

diff --git a/conf/widgetconfigurationtoolsbase.cpp b/conf/widgetconfigurationtoolsbase.cpp
index d30c5e8..1fe340e 100644
--- a/conf/widgetconfigurationtoolsbase.cpp
+++ b/conf/widgetconfigurationtoolsbase.cpp
@@ -26,7 +26,7 @@ WidgetConfigurationToolsBase::WidgetConfigurationToolsBase( QWidget * parent )
 {
     QHBoxLayout *hBoxLayout = new QHBoxLayout( this );
     m_list = new QListWidget( this );
-    m_list->setIconSize( QSize( 64, 64 ) );
+    m_list->setIconSize( QSize( 32, 32 ) );
     hBoxLayout->addWidget( m_list );
 
     QVBoxLayout *vBoxLayout = new QVBoxLayout();
diff --git a/core/document.cpp b/core/document.cpp
index 564c647..9f64d7f 100644
--- a/core/document.cpp
+++ b/core/document.cpp
@@ -1525,7 +1525,7 @@ void DocumentPrivate::refreshPixmaps( int pageNumber )
     for ( ; it != itEnd; ++it )
     {
         QSize size = (*it).m_pixmap->size();
-        PixmapRequest * p = new PixmapRequest( it.key(), pageNumber, size.width(), size.height(), 1, PixmapRequest::Asynchronous );
+        PixmapRequest * p = new PixmapRequest( it.key(), pageNumber, size.width() / qApp->devicePixelRatio(), size.height() / qApp->devicePixelRatio(), 1, PixmapRequest::Asynchronous );
         p->d->mForce = true;
         requestedPixmaps.push_back( p );
     }
@@ -1537,7 +1537,7 @@ void DocumentPrivate::refreshPixmaps( int pageNumber )
         {
             tilesManager->markDirty();
 
-            PixmapRequest * p = new PixmapRequest( observer, pageNumber, tilesManager->width(), tilesManager->height(), 1, PixmapRequest::Asynchronous );
+            PixmapRequest * p = new PixmapRequest( observer, pageNumber, tilesManager->width() / qApp->devicePixelRatio(), tilesManager->height() / qApp->devicePixelRatio(), 1, PixmapRequest::Asynchronous );
 
             NormalizedRect tilesRect;
 
diff --git a/core/generator.cpp b/core/generator.cpp
index f884337..004197d 100644
--- a/core/generator.cpp
+++ b/core/generator.cpp
@@ -12,6 +12,7 @@
 #include "generator_p.h"
 #include "observer.h"
 
+#include <QApplication>
 #include <qeventloop.h>
 #include <QtPrintSupport/QPrinter>
 
@@ -490,8 +491,8 @@ PixmapRequest::PixmapRequest( DocumentObserver *observer, int pageNumber, int wi
 {
     d->mObserver = observer;
     d->mPageNumber = pageNumber;
-    d->mWidth = width;
-    d->mHeight = height;
+    d->mWidth = ceil(width * qApp->devicePixelRatio());
+    d->mHeight = ceil(height * qApp->devicePixelRatio());
     d->mPriority = priority;
     d->mFeatures = features;
     d->mForce = false;
diff --git a/shell/main.cpp b/shell/main.cpp
index 27a998b..ca3833c 100644
--- a/shell/main.cpp
+++ b/shell/main.cpp
@@ -29,8 +29,9 @@
 
 int main(int argc, char** argv)
 {
-    QApplication app(argc, argv);
+    QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
 
+    QApplication app(argc, argv);
     KLocalizedString::setApplicationDomain("okular");
 
     KAboutData aboutData = okularAboutData();
diff --git a/ui/data/CMakeLists.txt b/ui/data/CMakeLists.txt
index e714c40..e177d51 100644
--- a/ui/data/CMakeLists.txt
+++ b/ui/data/CMakeLists.txt
@@ -10,12 +10,17 @@ install(FILES
 # install annotation tool images
 install(FILES
    tool-base-okular.png
+   tool-base-okular@2x.png
    tool-highlighter-okular-colorizable.png
+   tool-highlighter-okular-colorizable@2x.png
    tool-ink-okular-colorizable.png
+   tool-ink-okular-colorizable@2x.png
    tool-note.png
    tool-note-okular-colorizable.png
+   tool-note-okular-colorizable@2x.png
    tool-note-inline.png
    tool-note-inline-okular-colorizable.png
+   tool-note-inline-okular-colorizable@2x.png
    DESTINATION ${KDE_INSTALL_DATADIR}/okular/pics)
 # install annotation page images
 install(FILES
diff --git a/ui/data/tool-base-okular@2x.png b/ui/data/tool-base-okular@2x.png
new file mode 100644
index 0000000..973b448
Binary files /dev/null and b/ui/data/tool-base-okular@2x.png differ
diff --git a/ui/data/tool-highlighter-okular-colorizable@2x.png b/ui/data/tool-highlighter-okular-colorizable@2x.png
new file mode 100644
index 0000000..036b548
Binary files /dev/null and b/ui/data/tool-highlighter-okular-colorizable@2x.png differ
diff --git a/ui/data/tool-ink-okular-colorizable@2x.png b/ui/data/tool-ink-okular-colorizable@2x.png
new file mode 100644
index 0000000..7e02a79
Binary files /dev/null and b/ui/data/tool-ink-okular-colorizable@2x.png differ
diff --git a/ui/data/tool-note-inline-okular-colorizable@2x.png b/ui/data/tool-note-inline-okular-colorizable@2x.png
new file mode 100644
index 0000000..c80dc8f
Binary files /dev/null and b/ui/data/tool-note-inline-okular-colorizable@2x.png differ
diff --git a/ui/data/tool-note-okular-colorizable@2x.png b/ui/data/tool-note-okular-colorizable@2x.png
new file mode 100644
index 0000000..dbdd3d9
Binary files /dev/null and b/ui/data/tool-note-okular-colorizable@2x.png differ
diff --git a/ui/pagepainter.cpp b/ui/pagepainter.cpp
index 4b7e29a..94514a7 100644
--- a/ui/pagepainter.cpp
+++ b/ui/pagepainter.cpp
@@ -18,6 +18,7 @@
 #include <kiconloader.h>
 #include <QtCore/QDebug>
 #include <QApplication>
+#include <QIcon>
 
 // system includes
 #include <math.h>
@@ -35,7 +36,7 @@
 #include "settings_core.h"
 #include "ui/debug_ui.h"
 
-Q_GLOBAL_STATIC_WITH_ARGS( QPixmap, busyPixmap, ( KIconLoader::global()->loadIcon(QLatin1String("okular"), KIconLoader::NoGroup, 32, KIconLoader::DefaultState, QStringList(), 0, true) ) )
+Q_GLOBAL_STATIC_WITH_ARGS( QPixmap, busyPixmap, ( KIconLoader::global()->loadIcon(QLatin1String("okular"), KIconLoader::NoGroup, IconSize(KIconLoader::Desktop), KIconLoader::DefaultState, QStringList(), 0, true) ) )
 
 #define TEXTANNOTATION_ICONSIZE 24
 
@@ -62,11 +63,22 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
     Okular::DocumentObserver *observer, int flags, int scaledWidth, int scaledHeight, const QRect &limits,
     const Okular::NormalizedRect &crop, Okular::NormalizedPoint *viewPortPoint )
 {
+    qreal dpr = destPainter->device()->devicePixelRatioF();
+
     /* Calculate the cropped geometry of the page */
     QRect scaledCrop = crop.geometry( scaledWidth, scaledHeight );
+
+    /* variables prefixed with d are in the device pixels coordinate system, which translates to the rendered output - that means,
+     * multiplied with the device pixel ratio of the target PaintDevice */
+    const QRect dScaledCrop(QRectF(scaledCrop.x() * dpr, scaledCrop.y() * dpr, scaledCrop.width() * dpr, scaledCrop.height() * dpr).toAlignedRect());
+
     int croppedWidth = scaledCrop.width();
     int croppedHeight = scaledCrop.height();
 
+    int dScaledWidth = ceil(scaledWidth * dpr);
+    int dScaledHeight = ceil(scaledHeight * dpr);
+    const QRect dLimits(QRectF(limits.x() * dpr, limits.y() * dpr, limits.width() * dpr, limits.height() * dpr).toAlignedRect());
+
     QColor paperColor = Qt::white;
     QColor backgroundColor = paperColor;
     if ( Okular::SettingsCore::changeColors() )
@@ -89,22 +101,28 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
     destPainter->fillRect( limits, backgroundColor );
 
     const bool hasTilesManager = page->hasTilesManager( observer );
-    const QPixmap *pixmap = 0;
+    QPixmap pixmap;
 
     if ( !hasTilesManager )
     {
         /** 1 - RETRIEVE THE 'PAGE+ID' PIXMAP OR A SIMILAR 'PAGE' ONE **/
-        pixmap = page->_o_nearestPixmap( observer, scaledWidth, scaledHeight );
+        const QPixmap *p = page->_o_nearestPixmap( observer, dScaledWidth, dScaledHeight );
+
+        if (p != NULL) {
+            pixmap = *p;
+            pixmap.setDevicePixelRatio( qApp->devicePixelRatio() );
+        }
 
         /** 1B - IF NO PIXMAP, DRAW EMPTY PAGE **/
-        double pixmapRescaleRatio = pixmap ? scaledWidth / (double)pixmap->width() : -1;
-        long pixmapPixels = pixmap ? (long)pixmap->width() * (long)pixmap->height() : 0;
-        if ( !pixmap || pixmapRescaleRatio > 20.0 || pixmapRescaleRatio < 0.25 ||
-             (scaledWidth > pixmap->width() && pixmapPixels > 60000000L) )
+        double pixmapRescaleRatio = !pixmap.isNull() ? dScaledWidth / (double)pixmap.width() : -1;
+        long pixmapPixels = !pixmap.isNull() ? (long)pixmap.width() * (long)pixmap.height() : 0;
+        if ( pixmap.isNull() || pixmapRescaleRatio > 20.0 || pixmapRescaleRatio < 0.25 ||
+             (dScaledWidth > pixmap.width() && pixmapPixels > 60000000L) )
         {
             // draw something on the blank page: the okular icon or a cross (as a fallback)
             if ( !busyPixmap()->isNull() )
             {
+                busyPixmap->setDevicePixelRatio(dpr);
                 destPainter->drawPixmap( QPoint( 10, 10 ), *busyPixmap() );
             }
             else
@@ -135,10 +153,10 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
     if ( canDrawHighlights || canDrawTextSelection || canDrawAnnotations )
     {
         // precalc normalized 'limits rect' for intersection
-        double nXMin = ( (double)limits.left() / (double)scaledWidth ) + crop.left,
-               nXMax = ( (double)limits.right() / (double)scaledWidth )  + crop.left,
-               nYMin = ( (double)limits.top() / (double)scaledHeight ) + crop.top,
-               nYMax = ( (double)limits.bottom() / (double)scaledHeight ) + crop.top;
+        double nXMin = ( (double)limits.left() / dScaledWidth ) + crop.left,
+               nXMax = ( (double)limits.right() / dScaledWidth )  + crop.left,
+               nYMin = ( (double)limits.top() / dScaledHeight ) + crop.top,
+               nYMax = ( (double)limits.bottom() / dScaledHeight ) + crop.top;
         // append all highlights inside limits to their list
         if ( canDrawHighlights )
         {
@@ -240,6 +258,8 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
     QPixmap * backPixmap = 0;
     QPainter * mixedPainter = 0;
     QRect limitsInPixmap = limits.translated( scaledCrop.topLeft() );
+    QRect dLimitsInPixmap = dLimits.translated( dScaledCrop.topLeft() );
+
         // limits within full (scaled but uncropped) pixmap
 
     /** 4A -- REGULAR FLOW. PAINT PIXMAP NORMAL OR RESCALED USING GIVEN QPAINTER **/
@@ -254,32 +274,30 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
             {
                 const Okular::Tile &tile = *tIt;
                 QRect tileRect = tile.rect().geometry( scaledWidth, scaledHeight ).translated( -scaledCrop.topLeft() );
+                QRect dTileRect = QRectF(tileRect.x() * dpr, tileRect.y() * dpr, tileRect.width() * dpr, tileRect.height() * dpr).toAlignedRect();
                 QRect limitsInTile = limits & tileRect;
+                QRectF dLimitsInTile = dLimits & dTileRect;
+
                 if ( !limitsInTile.isEmpty() )
                 {
-                    if ( tile.pixmap()->width() == tileRect.width() && tile.pixmap()->height() == tileRect.height() )
-                        destPainter->drawPixmap( limitsInTile.topLeft(), *(tile.pixmap()),
-                                limitsInTile.translated( -tileRect.topLeft() ) );
-                    else
-                        destPainter->drawPixmap( tileRect, *(tile.pixmap()) );
+                    QPixmap* tilePixmap = tile.pixmap();
+                    tilePixmap->setDevicePixelRatio( qApp->devicePixelRatio() );
+
+                    if ( tilePixmap->width() == dTileRect.width() && tilePixmap->height() == dTileRect.height() ) {
+                        destPainter->drawPixmap( limitsInTile.topLeft(), *tilePixmap,
+                                dLimitsInTile.translated( -dTileRect.topLeft() ) );
+                    } else {
+                        destPainter->drawPixmap( tileRect, *tilePixmap );
+                    }
                 }
                 tIt++;
             }
         }
         else
         {
-            // 4A.1. if size is ok, draw the page pixmap using painter
-            if ( pixmap->width() == scaledWidth && pixmap->height() == scaledHeight )
-                destPainter->drawPixmap( limits.topLeft(), *pixmap, limitsInPixmap );
-
-            // else draw a scaled portion of the magnified pixmap
-            else
-            {
-                QImage destImage;
-                scalePixmapOnImage( destImage, pixmap, scaledWidth, scaledHeight, limitsInPixmap );
-                destPainter->drawImage( limits.left(), limits.top(), destImage, 0, 0,
-                                         limits.width(),limits.height() );
-            }
+            QPixmap scaledCroppedPixmap = pixmap.scaled(dScaledWidth, dScaledHeight).copy(dLimitsInPixmap);
+            scaledCroppedPixmap.setDevicePixelRatio(dpr);
+            destPainter->drawPixmap( limits.topLeft(), scaledCroppedPixmap, QRectF(0, 0, dLimits.width(),dLimits.height()));
         }
 
         // 4A.2. active painter is the one passed to this method
@@ -289,13 +307,13 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
     else
     {
         // the image over which we are going to draw
-        QImage backImage;
+        QImage backImage = QImage( dLimits.width(), dLimits.height(), QImage::Format_ARGB32_Premultiplied );
+        backImage.setDevicePixelRatio(dpr);
+        backImage.fill( paperColor );
+        QPainter p( &backImage );
 
         if ( hasTilesManager )
         {
-            backImage = QImage( limits.width(), limits.height(), QImage::Format_ARGB32_Premultiplied );
-            backImage.fill( paperColor.rgb() );
-            QPainter p( &backImage );
             const Okular::NormalizedRect normalizedLimits( limitsInPixmap, scaledWidth, scaledHeight );
             const QList<Okular::Tile> tiles = page->tilesAt( observer, normalizedLimits );
             QList<Okular::Tile>::const_iterator tIt = tiles.constBegin(), tEnd = tiles.constEnd();
@@ -303,36 +321,42 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
             {
                 const Okular::Tile &tile = *tIt;
                 QRect tileRect = tile.rect().geometry( scaledWidth, scaledHeight ).translated( -scaledCrop.topLeft() );
+                QRect dTileRect(QRectF(tileRect.x() * dpr, tileRect.y() * dpr, tileRect.width() * dpr, tileRect.height() * dpr).toAlignedRect());
                 QRect limitsInTile = limits & tileRect;
+                QRect dLimitsInTile = dLimits & dTileRect;
+
                 if ( !limitsInTile.isEmpty() )
                 {
-                    if ( tile.pixmap()->width() == tileRect.width() && tile.pixmap()->height() == tileRect.height() )
+                    QPixmap* tilePixmap = tile.pixmap();
+                    tilePixmap->setDevicePixelRatio( qApp->devicePixelRatio() );
+
+                    if ( tilePixmap->width() == dTileRect.width() && tilePixmap->height() == dTileRect.height() )
                     {
-                        p.drawPixmap( limitsInTile.translated( -limits.topLeft() ).topLeft(), *(tile.pixmap()),
-                                limitsInTile.translated( -tileRect.topLeft() ) );
+                        p.drawPixmap( limitsInTile.translated( -limits.topLeft() ).topLeft(), *tilePixmap,
+                                dLimitsInTile.translated( -dTileRect.topLeft() ) );
                     }
                     else
                     {
-                        double xScale = tile.pixmap()->width() / (double)tileRect.width();
-                        double yScale = tile.pixmap()->height() / (double)tileRect.height();
+                        double xScale = tilePixmap->width() / (double)dTileRect.width();
+                        double yScale = tilePixmap->height() / (double)dTileRect.height();
                         QTransform transform( xScale, 0, 0, yScale, 0, 0 );
-                        p.drawPixmap( limitsInTile.translated( -limits.topLeft() ), *(tile.pixmap()),
-                                transform.mapRect( limitsInTile ).translated( -transform.mapRect( tileRect ).topLeft() ) );
+                        p.drawPixmap( limitsInTile.translated( -limits.topLeft() ), *tilePixmap,
+                                transform.mapRect( dLimitsInTile ).translated( -transform.mapRect( dTileRect ).topLeft() ) );
                     }
                 }
                 ++tIt;
             }
-            p.end();
         }
         else
         {
             // 4B.1. draw the page pixmap: normal or scaled
-            if ( pixmap->width() == scaledWidth && pixmap->height() == scaledHeight )
-                cropPixmapOnImage( backImage, pixmap, limitsInPixmap );
-            else
-                scalePixmapOnImage( backImage, pixmap, scaledWidth, scaledHeight, limitsInPixmap );
+            QPixmap scaledCroppedPixmap = pixmap.scaled(dScaledWidth, dScaledHeight).copy(dLimitsInPixmap);
+            scaledCroppedPixmap.setDevicePixelRatio(dpr);
+            p.drawPixmap( 0, 0, scaledCroppedPixmap );
         }
 
+        p.end();
+
         // 4B.2. modify pixmap following accessibility settings
         if ( bufferAccessibility )
         {
@@ -370,6 +394,7 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
                     break;
             }
         }
+
         // 4B.3. highlight rects in page
         if ( bufferedHighlights )
         {
@@ -387,6 +412,7 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
                 painter.fillRect(highlightRect, highlightColor);
             }
         }
+
         // 4B.4. paint annotations [COMPOSITED ONES]
         if ( bufferedAnnotations )
         {
@@ -579,7 +605,6 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
                 }
             } // end current annotation drawing
         }
-
         if(viewPortPoint)
         {
             QPainter painter(&backImage);
@@ -609,6 +634,7 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
 
         // 4B.5. create the back pixmap converting from the local image
         backPixmap = new QPixmap( QPixmap::fromImage( backImage ) );
+        backPixmap->setDevicePixelRatio(dpr);
 
         // 4B.6. create a painter over the pixmap and set it as the active one
         mixedPainter = new QPainter( backPixmap );
@@ -641,6 +667,7 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
             QRect annotRect = annotBoundary.intersected( limits );
             QRect innerRect( annotRect.left() - annotBoundary.left(), annotRect.top() -
                     annotBoundary.top(), annotRect.width(), annotRect.height() );
+            QRectF dInnerRect(innerRect.x() * dpr, innerRect.y() * dpr, innerRect.width() * dpr, innerRect.height() * dpr);
 
             Okular::Annotation::SubType type = a->subType();
 
@@ -684,23 +711,24 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
                     QPixmap pixmap = GuiUtils::iconLoader()->loadIcon( text->textIcon().toLower(), KIconLoader::User, 32, KIconLoader::DefaultState, QStringList(), &path, true );
                     if ( path.isEmpty() )
                         pixmap = GuiUtils::iconLoader()->loadIcon( text->textIcon().toLower(), KIconLoader::NoGroup, 32 );
-                    QImage scaledImage;
-                    QRect annotBoundary2 = QRect( annotBoundary.topLeft(), QSize( TEXTANNOTATION_ICONSIZE, TEXTANNOTATION_ICONSIZE ) );
+                    QRect annotBoundary2 = QRect( annotBoundary.topLeft(), QSize( TEXTANNOTATION_ICONSIZE * dpr, TEXTANNOTATION_ICONSIZE * dpr ) );
                     QRect annotRect2 = annotBoundary2.intersected( limits );
                     QRect innerRect2( annotRect2.left() - annotBoundary2.left(), annotRect2.top() -
                     annotBoundary2.top(), annotRect2.width(), annotRect2.height() );
-                    scalePixmapOnImage( scaledImage, &pixmap,
-                                        TEXTANNOTATION_ICONSIZE, TEXTANNOTATION_ICONSIZE,
-                                        innerRect2, QImage::Format_ARGB32 );
+
+                    QPixmap scaledCroppedPixmap = pixmap.scaled(TEXTANNOTATION_ICONSIZE * dpr, TEXTANNOTATION_ICONSIZE * dpr).copy(dInnerRect.toAlignedRect());
+                    scaledCroppedPixmap.setDevicePixelRatio(dpr);
+                    QImage scaledCroppedImage = scaledCroppedPixmap.toImage();
+
                     // if the annotation color is valid (ie it was set), then
                     // use it to colorize the icon, otherwise the icon will be
                     // "gray"
                     if ( a->style().color().isValid() )
-                        GuiUtils::colorizeImage( scaledImage, a->style().color(), opacity );
-                    pixmap = QPixmap::fromImage( scaledImage );
+                        GuiUtils::colorizeImage( scaledCroppedImage, a->style().color(), opacity );
+                    pixmap = QPixmap::fromImage( scaledCroppedImage );
 
-                // draw the mangled image to painter
-                    mixedPainter->drawPixmap( annotRect.topLeft(), pixmap );
+                    // draw the mangled image to painter
+                    mixedPainter->drawPixmap( annotRect.topLeft(), pixmap);
                 }
 
             }
@@ -713,12 +741,16 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
                 QPixmap pixmap = GuiUtils::loadStamp( stamp->stampIconName(), annotBoundary.size() );
                 if ( !pixmap.isNull() ) // should never happen but can happen on huge sizes
                 {
-                    QImage scaledImage;
-                    scalePixmapOnImage( scaledImage, &pixmap, annotBoundary.width(),
-                                        annotBoundary.height(), innerRect, QImage::Format_ARGB32 );
+                    const QRect dInnerRect(QRectF(innerRect.x() * dpr, innerRect.y() * dpr, innerRect.width() * dpr, innerRect.height() * dpr).toAlignedRect());
+
+                    QPixmap scaledCroppedPixmap = pixmap.scaled(annotBoundary.width() * dpr, annotBoundary.height() * dpr).copy(dInnerRect);
+                    scaledCroppedPixmap.setDevicePixelRatio(dpr);
+
+                    QImage scaledCroppedImage = scaledCroppedPixmap.toImage();
+
                     if ( opacity < 255 )
-                        changeImageAlpha( scaledImage, opacity );
-                    pixmap = QPixmap::fromImage( scaledImage );
+                        changeImageAlpha( scaledCroppedImage, opacity );
+                    pixmap = QPixmap::fromImage( scaledCroppedImage );
 
                     // draw the scaled and al
                     mixedPainter->drawPixmap( annotRect.topLeft(), pixmap );
@@ -823,8 +855,10 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
 /** Private Helpers :: Pixmap conversion **/
 void PagePainter::cropPixmapOnImage( QImage & dest, const QPixmap * src, const QRect & r )
 {
+    qreal dpr = src->devicePixelRatioF();
+
     // handle quickly the case in which the whole pixmap has to be converted
-    if ( r == QRect( 0, 0, src->width(), src->height() ) )
+    if ( r == QRect( 0, 0, src->width() / dpr, src->height() / dpr ) )
     {
         dest = src->toImage();
         dest = dest.convertToFormat(QImage::Format_ARGB32_Premultiplied);
@@ -832,7 +866,8 @@ void PagePainter::cropPixmapOnImage( QImage & dest, const QPixmap * src, const Q
     // else copy a portion of the src to an internal pixmap (smaller) and convert it
     else
     {
-        QImage croppedImage( r.width(), r.height(), QImage::Format_ARGB32_Premultiplied );
+        QImage croppedImage( r.width() * dpr, r.height() * dpr, QImage::Format_ARGB32_Premultiplied );
+        croppedImage.setDevicePixelRatio(dpr);
         QPainter p( &croppedImage );
         p.drawPixmap( 0, 0, *src, r.left(), r.top(), r.width(), r.height() );
         p.end();
@@ -866,40 +901,6 @@ void PagePainter::recolor(QImage *image, const QColor &foreground, const QColor
     }
 }
 
-void PagePainter::scalePixmapOnImage ( QImage & dest, const QPixmap * src,
-    int scaledWidth, int scaledHeight, const QRect & cropRect, QImage::Format format )
-{
-    // {source, destination, scaling} params
-    int srcWidth = src->width(),
-        srcHeight = src->height(),
-        destLeft = cropRect.left(),
-        destTop = cropRect.top(),
-        destWidth = cropRect.width(),
-        destHeight = cropRect.height();
-
-    // destination image (same geometry as the pageLimits rect)
-    dest = QImage( destWidth, destHeight, format );
-    unsigned int * destData = (unsigned int *)dest.bits();
-
-    // source image (1:1 conversion from pixmap)
-    QImage srcImage = src->toImage().convertToFormat(format);
-    unsigned int * srcData = (unsigned int *)srcImage.bits();
-
-    // precalc the x correspondancy conversion in a lookup table
-    QVarLengthArray<unsigned int> xOffset( destWidth );
-    for ( int x = 0; x < destWidth; x++ )
-        xOffset[ x ] = ((x + destLeft) * srcWidth) / scaledWidth;
-
-    // for each pixel of the destination image apply the color of the
-    // corresponsing pixel on the source image (note: keep parenthesis)
-    for ( int y = 0; y < destHeight; y++ )
-    {
-        unsigned int srcOffset = srcWidth * (((destTop + y) * srcHeight) / scaledHeight);
-        for ( int x = 0; x < destWidth; x++ )
-            (*destData++) = srcData[ srcOffset + xOffset[x] ];
-    }
-}
-
 /** Private Helpers :: Image Drawing **/
 // from Arthur - qt4
 static inline int qt_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; }
diff --git a/ui/pagepainter.h b/ui/pagepainter.h
index 1300c9b..c3cb3db 100644
--- a/ui/pagepainter.h
+++ b/ui/pagepainter.h
@@ -56,12 +56,6 @@ class Q_DECL_EXPORT PagePainter
         static void cropPixmapOnImage( QImage & dest, const QPixmap * src, const QRect & r );
         static void recolor(QImage *image, const QColor &foreground, const QColor &background);
 
-        // create an image taking the 'cropRect' portion of an image scaled
-        // to 'scaledWidth' by 'scaledHeight' pixels. cropRect must be inside
-        // the QRect(0,0, scaledWidth,scaledHeight)
-        static void scalePixmapOnImage( QImage & dest, const QPixmap *src,
-            int scaledWidth, int scaledHeight, const QRect & cropRect, QImage::Format format = QImage::Format_ARGB32_Premultiplied );
-
         // set the alpha component of the image to a given value
         static void changeImageAlpha( QImage & image, unsigned int alpha );
 
diff --git a/ui/pageview.cpp b/ui/pageview.cpp
index 7ceefcb..34b7bbd 100644
--- a/ui/pageview.cpp
+++ b/ui/pageview.cpp
@@ -1651,8 +1651,10 @@ void PageView::paintEvent(QPaintEvent *pe)
             if ( wantCompositing && Okular::Settings::enableCompositing() )
             {
                 // create pixmap and open a painter over it (contents{left,top} becomes pixmap {0,0})
-                QPixmap doubleBuffer( contentsRect.size() );
+                QPixmap doubleBuffer( contentsRect.size() * devicePixelRatioF() );
+                doubleBuffer.setDevicePixelRatio(devicePixelRatioF());
                 QPainter pixmapPainter( &doubleBuffer );
+
                 pixmapPainter.translate( -contentsRect.left(), -contentsRect.top() );
 
                 // 1) Layer 0: paint items and clear bg on unpainted rects
@@ -1666,11 +1668,12 @@ void PageView::paintEvent(QPaintEvent *pe)
                     if ( blendRect.isValid() )
                     {
                         // grab current pixmap into a new one to colorize contents
-                        QPixmap blendedPixmap( blendRect.width(), blendRect.height() );
+                        QPixmap blendedPixmap( blendRect.width() * devicePixelRatioF(), blendRect.height() * devicePixelRatioF() );
+                        blendedPixmap.setDevicePixelRatio(devicePixelRatioF());
                         QPainter p( &blendedPixmap );
                         p.drawPixmap( 0, 0, doubleBuffer,
                                     blendRect.left() - contentsRect.left(), blendRect.top() - contentsRect.top(),
-                                    blendRect.width(), blendRect.height() );
+                                    blendRect.width() * devicePixelRatioF(), blendRect.height() * devicePixelRatioF() );
 
                         QColor blCol = selBlendColor.dark( 140 );
                         blCol.setAlphaF( 0.2 );
@@ -1697,11 +1700,12 @@ void PageView::paintEvent(QPaintEvent *pe)
                         if ( blendRect.isValid() )
                         {
                             // grab current pixmap into a new one to colorize contents
-                            QPixmap blendedPixmap( blendRect.width(), blendRect.height() );
+                            QPixmap blendedPixmap( blendRect.width()  * devicePixelRatioF(), blendRect.height()  * devicePixelRatioF() );
+                            blendedPixmap.setDevicePixelRatio(devicePixelRatioF());
                             QPainter p( &blendedPixmap );
                             p.drawPixmap( 0, 0, doubleBuffer,
                                         blendRect.left() - contentsRect.left(), blendRect.top() - contentsRect.top(),
-                                        blendRect.width(), blendRect.height() );
+                                        blendRect.width() * devicePixelRatioF(), blendRect.height() * devicePixelRatioF() );
 
                             QColor blCol = d->mouseSelectionColor.dark( 140 );
                             blCol.setAlphaF( 0.2 );
diff --git a/ui/pageview.h b/ui/pageview.h
index 10e2a8b..2b0de2b 100644
--- a/ui/pageview.h
+++ b/ui/pageview.h
@@ -36,6 +36,7 @@ class DocumentViewport;
 class Annotation;
 class MovieAction;
 class RenditionAction;
+class PixmapRequest;
 }
 
 class FormWidgetIface;
diff --git a/ui/pageviewannotator.cpp b/ui/pageviewannotator.cpp
index 89dc8bf..87a79d9 100644
--- a/ui/pageviewannotator.cpp
+++ b/ui/pageviewannotator.cpp
@@ -1111,11 +1111,18 @@ QString PageViewAnnotator::defaultToolName( const QDomElement &toolElement )
 
 QPixmap PageViewAnnotator::makeToolPixmap( const QDomElement &toolElement )
 {
-    QPixmap pixmap( 32, 32 );
+    QPixmap pixmap( 32 * qApp->devicePixelRatio(), 32 * qApp->devicePixelRatio() );
+    pixmap.setDevicePixelRatio( qApp->devicePixelRatio() );
     const QString annotType = toolElement.attribute( QStringLiteral("type") );
 
+    // Load HiDPI variant on HiDPI screen
+    QString imageVariant;
+    if ( qApp->devicePixelRatio() > 1.05 ) {
+        imageVariant = "@2x";
+    }
+
     // Load base pixmap. We'll draw on top of it
-    pixmap.load( QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("okular/pics/tool-base-okular.png") ) );
+    pixmap.load( QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString("okular/pics/tool-base-okular" + imageVariant + ".png") ) );
 
     /* Parse color, innerColor and icon (if present) */
     QColor engineColor, innerColor;
@@ -1149,7 +1156,7 @@ QPixmap PageViewAnnotator::makeToolPixmap( const QDomElement &toolElement )
     }
     else if ( annotType == QLatin1String("highlight") )
     {
-        QImage overlay( QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("okular/pics/tool-highlighter-okular-colorizable.png") ) );
+        QImage overlay( QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString("okular/pics/tool-highlighter-okular-colorizable" + imageVariant + ".png") ) );
         QImage colorizedOverlay = overlay;
         GuiUtils::colorizeImage( colorizedOverlay, engineColor );
 
@@ -1159,7 +1166,7 @@ QPixmap PageViewAnnotator::makeToolPixmap( const QDomElement &toolElement )
     }
     else if ( annotType == QLatin1String("ink") )
     {
-        QImage overlay( QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("okular/pics/tool-ink-okular-colorizable.png") ) );
+        QImage overlay( QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString("okular/pics/tool-ink-okular-colorizable" + imageVariant + ".png") ) );
         QImage colorizedOverlay = overlay;
         GuiUtils::colorizeImage( colorizedOverlay, engineColor );
 
@@ -1169,13 +1176,13 @@ QPixmap PageViewAnnotator::makeToolPixmap( const QDomElement &toolElement )
     }
     else if ( annotType == QLatin1String("note-inline") )
     {
-        QImage overlay( QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("okular/pics/tool-note-inline-okular-colorizable.png") ) );
+        QImage overlay( QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString("okular/pics/tool-note-inline-okular-colorizable" + imageVariant + ".png") ) );
         GuiUtils::colorizeImage( overlay, engineColor );
         p.drawImage( QPoint(0,0), overlay );
     }
     else if ( annotType == QLatin1String("note-linked") )
     {
-        QImage overlay( QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("okular/pics/tool-note-okular-colorizable.png") ) );
+        QImage overlay( QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString("okular/pics/tool-note-okular-colorizable.png" + imageVariant + ".png") ) );
         GuiUtils::colorizeImage( overlay, engineColor );
         p.drawImage( QPoint(0,0), overlay );
     }
diff --git a/ui/presentationwidget.cpp b/ui/presentationwidget.cpp
index b49b437..d54dc46 100644
--- a/ui/presentationwidget.cpp
+++ b/ui/presentationwidget.cpp
@@ -96,6 +96,7 @@ struct PresentationFrame
         geometry.setRect( ( width - pageWidth ) / 2,
                           ( height - pageHeight ) / 2,
                           pageWidth, pageHeight );
+
         Q_FOREACH ( VideoWidget *vw, videoWidgets )
         {
             const Okular::NormalizedRect r = vw->normGeometry();
@@ -451,7 +452,7 @@ void PresentationWidget::notifyCurrentPageChanged( int previousPage, int current
 
         // if pixmap not inside the Okular::Page we request it and wait for
         // notifyPixmapChanged call or else we can proceed to pixmap generation
-        if ( !frame->page->hasPixmap( this, pixW, pixH ) )
+        if ( !frame->page->hasPixmap( this, ceil(pixW * qApp->devicePixelRatio()), ceil(pixH * qApp->devicePixelRatio()) ) )
         {
             requestPixmaps();
         }
@@ -780,6 +781,8 @@ void PresentationWidget::mouseMoveEvent( QMouseEvent * e )
 
 void PresentationWidget::paintEvent( QPaintEvent * pe )
 {
+    qreal dpr = devicePixelRatioF();
+
     if ( m_inBlackScreenMode )
     {
         QPainter painter( this );
@@ -824,28 +827,32 @@ void PresentationWidget::paintEvent( QPaintEvent * pe )
         if ( !r.isValid() )
             continue;
 #ifdef ENABLE_PROGRESS_OVERLAY
+        const QRect dR(QRectF(r.x() * dpr, r.y() * dpr, r.width() * dpr, r.height() * dpr).toAlignedRect());
         if ( Okular::Settings::slidesShowProgress() && r.intersects( m_overlayGeometry ) )
         {
             // backbuffer the overlay operation
-            QPixmap backPixmap( r.size() );
+            QPixmap backPixmap( dR.size() );
+            backPixmap.setDevicePixelRatio( dpr );
             QPainter pixPainter( &backPixmap );
 
             // first draw the background on the backbuffer
-            pixPainter.drawPixmap( QPoint(0,0), m_lastRenderedPixmap, r );
+            pixPainter.drawPixmap( QPoint(0,0), m_lastRenderedPixmap, dR );
 
             // then blend the overlay (a piece of) over the background
             QRect ovr = m_overlayGeometry.intersected( r );
-            pixPainter.drawPixmap( ovr.left() - r.left(), ovr.top() - r.top(),
-                m_lastRenderedOverlay, ovr.left() - m_overlayGeometry.left(),
-                ovr.top() - m_overlayGeometry.top(), ovr.width(), ovr.height() );
+            pixPainter.drawPixmap( (ovr.left() - r.left()), (ovr.top() - r.top()),
+                m_lastRenderedOverlay, (ovr.left() - m_overlayGeometry.left()) * dpr,
+                (ovr.top() - m_overlayGeometry.top()) * dpr, ovr.width() * dpr, ovr.height() * dpr );
 
             // finally blit the pixmap to the screen
             pixPainter.end();
-            painter.drawPixmap( r.topLeft(), backPixmap, backPixmap.rect() );
+            const QRect backPixmapRect = backPixmap.rect();
+            const QRect dBackPixmapRect(QRectF(backPixmapRect.x() * dpr, backPixmapRect.y() * dpr, backPixmapRect.width() * dpr, backPixmapRect.height() * dpr).toAlignedRect());
+            painter.drawPixmap( r.topLeft(), backPixmap, dBackPixmapRect );
         } else
 #endif
         // copy the rendered pixmap to the screen
-        painter.drawPixmap( r.topLeft(), m_lastRenderedPixmap, r );
+        painter.drawPixmap( r.topLeft(), m_lastRenderedPixmap, dR );
     }
 
     // paint drawings
@@ -1001,7 +1008,10 @@ void PresentationWidget::generatePage( bool disableTransition )
 {
     if ( m_lastRenderedPixmap.isNull() )
     {
-        m_lastRenderedPixmap = QPixmap( m_width, m_height );
+        qreal dpr = qApp->devicePixelRatio();
+        m_lastRenderedPixmap = QPixmap( m_width * dpr, m_height * dpr );
+        m_lastRenderedPixmap.setDevicePixelRatio(dpr);
+
         m_previousPagePixmap = QPixmap();
     }
     else
@@ -1054,6 +1064,8 @@ void PresentationWidget::generatePage( bool disableTransition )
 
 void PresentationWidget::generateIntroPage( QPainter & p )
 {
+    qreal dpr = qApp->devicePixelRatio();
+
     // use a vertical gray gradient background
     int blend1 = m_height / 10,
         blend2 = 9 * m_height / 10;
@@ -1069,7 +1081,8 @@ void PresentationWidget::generateIntroPage( QPainter & p )
     }
 
     // draw okular logo in the four corners
-    QPixmap logo = DesktopIcon( QStringLiteral("okular"), 64 );
+    QPixmap logo = DesktopIcon( QStringLiteral("okular"), 64 * dpr );
+    logo.setDevicePixelRatio( dpr );
     if ( !logo.isNull() )
     {
         p.drawPixmap( 5, 5, logo );
@@ -1116,6 +1129,7 @@ void PresentationWidget::generateContentsPage( int pageNum, QPainter & p )
 
     // draw the page using the shared PagePainter class
     int flags = PagePainter::Accessibility | PagePainter::Highlights | PagePainter::Annotations;
+
     PagePainter::paintPageOnPainter( &p, frame->page, this, flags,
                                      geom.width(), geom.height(), geom );
 
@@ -1137,6 +1151,8 @@ inline int qt_div255(int x) { return (x + (x>>8) + 0x80) >> 8; }
 void PresentationWidget::generateOverlay()
 {
 #ifdef ENABLE_PROGRESS_OVERLAY
+    qreal dpr = qApp->devicePixelRatio();
+
     // calculate overlay geometry and resize pixmap if needed
     int side = m_width / 16;
     m_overlayGeometry.setRect( m_width - side - 4, 4, side, side );
@@ -1145,7 +1161,9 @@ void PresentationWidget::generateOverlay()
     // and the resulting image is smoothly scaled down. So here we open a
     // painter on the double sized pixmap.
     side *= 2;
-    QPixmap doublePixmap( side, side );
+
+    QPixmap doublePixmap( side * dpr, side * dpr );
+    doublePixmap.setDevicePixelRatio( dpr );
     doublePixmap.fill( Qt::black );
     QPainter pixmapPainter( &doublePixmap );
     pixmapPainter.setRenderHints( QPainter::Antialiasing );
@@ -1190,8 +1208,10 @@ void PresentationWidget::generateOverlay()
 
     // end drawing pixmap and halve image
     pixmapPainter.end();
-    QImage image( doublePixmap.toImage().scaled( side / 2, side / 2, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
+    QImage image( doublePixmap.toImage().scaled( (side / 2) * dpr, (side / 2) * dpr, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
+    image.setDevicePixelRatio( dpr );
     image = image.convertToFormat( QImage::Format_ARGB32 );
+    image.setDevicePixelRatio( dpr );
 
     // draw circular shadow using the same technique
     doublePixmap.fill( Qt::black );
@@ -1200,7 +1220,8 @@ void PresentationWidget::generateOverlay()
     pixmapPainter.setBrush( QColor( 0x80 ) );
     pixmapPainter.drawEllipse( 0, 0, side, side );
     pixmapPainter.end();
-    QImage shadow( doublePixmap.toImage().scaled( side / 2, side / 2, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
+    QImage shadow( doublePixmap.toImage().scaled( (side / 2) * dpr, (side / 2) * dpr, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
+    shadow.setDevicePixelRatio( dpr );
 
     // generate a 2 colors pixmap using mixing shadow (made with highlight color)
     // and image (made with highlightedText color)
@@ -1238,6 +1259,7 @@ void PresentationWidget::generateOverlay()
             data[i] = qRgba( cR, cG, cB, cA );
     }
     m_lastRenderedOverlay = QPixmap::fromImage( image );
+    m_lastRenderedOverlay.setDevicePixelRatio( dpr );
 
     // start the autohide timer
     //repaint( m_overlayGeometry ); // toggle with next line
@@ -1519,6 +1541,7 @@ void PresentationWidget::slotTransitionStep()
             QPainter pixmapPainter;
             m_currentPixmapOpacity += 1.0 / m_transitionSteps;
             m_lastRenderedPixmap = QPixmap( m_lastRenderedPixmap.size() );
+            m_lastRenderedPixmap.setDevicePixelRatio( qApp->devicePixelRatio() );
             m_lastRenderedPixmap.fill( Qt::transparent );
             pixmapPainter.begin( &m_lastRenderedPixmap );
             pixmapPainter.setCompositionMode( QPainter::CompositionMode_Source );
-- 
cgit v0.11.2

openSUSE Build Service is sponsored by