Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:42.3:Update
okular
HiDPI-support.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
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
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor