mirror of
https://invent.kde.org/graphics/okular
synced 2024-10-02 14:14:10 +00:00
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
This commit is contained in:
parent
6d7403ff13
commit
ecc1141e02
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
BIN
ui/data/tool-base-okular@2x.png
Normal file
BIN
ui/data/tool-base-okular@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
ui/data/tool-highlighter-okular-colorizable@2x.png
Normal file
BIN
ui/data/tool-highlighter-okular-colorizable@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
BIN
ui/data/tool-ink-okular-colorizable@2x.png
Normal file
BIN
ui/data/tool-ink-okular-colorizable@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
BIN
ui/data/tool-note-inline-okular-colorizable@2x.png
Normal file
BIN
ui/data/tool-note-inline-okular-colorizable@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 945 B |
BIN
ui/data/tool-note-okular-colorizable@2x.png
Normal file
BIN
ui/data/tool-note-okular-colorizable@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -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 = nullptr;
|
||||
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 = nullptr;
|
||||
QPainter * mixedPainter = nullptr;
|
||||
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; }
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -36,6 +36,7 @@ class DocumentViewport;
|
|||
class Annotation;
|
||||
class MovieAction;
|
||||
class RenditionAction;
|
||||
class PixmapRequest;
|
||||
}
|
||||
|
||||
class FormWidgetIface;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in a new issue