diff --git a/conf/widgetconfigurationtoolsbase.cpp b/conf/widgetconfigurationtoolsbase.cpp --- a/conf/widgetconfigurationtoolsbase.cpp +++ b/conf/widgetconfigurationtoolsbase.cpp @@ -26,7 +26,7 @@ { 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 --- a/core/document.cpp +++ b/core/document.cpp @@ -1525,7 +1525,7 @@ 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 @@ { 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 --- a/core/generator.cpp +++ b/core/generator.cpp @@ -12,6 +12,7 @@ #include "generator_p.h" #include "observer.h" +#include #include #include @@ -490,8 +491,8 @@ { 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 --- 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 --- a/ui/data/CMakeLists.txt +++ b/ui/data/CMakeLists.txt @@ -10,12 +10,17 @@ # 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ #include #include +#include // system includes #include @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ 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 tiles = page->tilesAt( observer, normalizedLimits ); QList::const_iterator tIt = tiles.constBegin(), tEnd = tiles.constEnd(); @@ -303,36 +321,42 @@ { 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 @@ break; } } + // 4B.3. highlight rects in page if ( bufferedHighlights ) { @@ -387,6 +412,7 @@ painter.fillRect(highlightRect, highlightColor); } } + // 4B.4. paint annotations [COMPOSITED ONES] if ( bufferedAnnotations ) { @@ -579,7 +605,6 @@ } } // end current annotation drawing } - if(viewPortPoint) { QPainter painter(&backImage); @@ -609,6 +634,7 @@ // 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 @@ 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 @@ 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 @@ 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 @@ /** 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 @@ // 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::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 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/pageview.h b/ui/pageview.h --- a/ui/pageview.h +++ b/ui/pageview.h @@ -36,6 +36,7 @@ class Annotation; class MovieAction; class RenditionAction; +class PixmapRequest; } class FormWidgetIface; diff --git a/ui/pageview.cpp b/ui/pageview.cpp --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -1648,8 +1648,10 @@ 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 @@ -1663,11 +1665,12 @@ 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 ); @@ -1694,11 +1697,12 @@ 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/pageviewannotator.cpp b/ui/pageviewannotator.cpp --- a/ui/pageviewannotator.cpp +++ b/ui/pageviewannotator.cpp @@ -1111,11 +1111,18 @@ 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 @@ } 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 @@ } 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 @@ } 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 --- a/ui/presentationwidget.cpp +++ b/ui/presentationwidget.cpp @@ -96,6 +96,7 @@ 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 @@ // 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::paintEvent( QPaintEvent * pe ) { + qreal dpr = devicePixelRatioF(); + if ( m_inBlackScreenMode ) { QPainter painter( this ); @@ -824,28 +827,32 @@ 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 @@ { 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::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 @@ } // 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 @@ // 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 @@ 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 @@ // 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 @@ // 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 @@ 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 @@ 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 @@ 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 );