From ed3559462759bf9b94d7b3e8f1ee289423fa9d17 Mon Sep 17 00:00:00 2001 From: Eugene Shalygin Date: Mon, 13 Jan 2014 01:15:55 +0100 Subject: [PATCH] Use DPI of current screen for PDF rendering Includes some fixes from Albert: * kscreen cmake fixes Don't make libkscreen mandatory, give the proper version we need * Fix the @since * Kill Resolution and use a QSizeF I first thought QSizeF didn't make sense, but well what's a dpi if not a number of pixels in width and some others in height? * Remove unwanted const * Remove unneeded utils.h includes * Fix comments on realDPIXY() * Make it compile in non X11 REVIEW: 111829 --- CMakeLists.txt | 8 ++++ config-okular.h.cmake | 3 ++ core/document.cpp | 12 ++++++ core/generator.cpp | 15 ++++++- core/generator.h | 17 +++++++- core/generator_p.h | 1 + core/utils.cpp | 58 +++++++++++++++++++++++++++- core/utils.h | 15 +++++++ generators/poppler/generator_pdf.cpp | 19 +++++---- generators/poppler/generator_pdf.h | 4 +- 10 files changed, 136 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 50e4018ba..63d2922fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,12 +10,16 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules) macro_optional_find_package(QImageBlitz) macro_log_feature(QIMAGEBLITZ_FOUND "QImageBlitz" "An image effects library" "http://sourceforge.net/projects/qimageblitz" TRUE "kdesupport" "Required to build Okular.") +macro_optional_find_package(LibKScreen) +macro_log_feature(LibKScreen_FOUND "LibKScreen" "KDE screen management library" "https://projects.kde.org/projects/kdereview/libkscreen" FALSE "1.0.2" "DPI detection support") + add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${KDE4_INCLUDES} ${QIMAGEBLITZ_INCLUDES} + ${LibKScreen_INCLUDE_DIR} ) add_subdirectory( active ) @@ -131,6 +135,10 @@ ENDIF(APPLE) target_link_libraries(okularcore ${OKULAR_IOKIT} ${KDE4_KIO_LIBS} ${KDE4_PHONON_LIBRARY} ${KDE4_KJSAPI_LIBRARY} ${MATH_LIB} ${KDE4_THREADWEAVER_LIBRARY} ) +if(LibKScreen_FOUND) + target_link_libraries(okularcore ${LibKScreen_LIBRARY}) +endif(LibKScreen_FOUND) + set_target_properties(okularcore PROPERTIES VERSION 3.0.0 SOVERSION 3 ) install(TARGETS okularcore ${INSTALL_TARGETS_DEFAULT_ARGS} ) diff --git a/config-okular.h.cmake b/config-okular.h.cmake index 7217f8d53..4b4b2eec3 100644 --- a/config-okular.h.cmake +++ b/config-okular.h.cmake @@ -1,2 +1,5 @@ /* Defines if force the use DRM in okular */ #define OKULAR_FORCE_DRM ${_OKULAR_FORCE_DRM} + +/* Defines if LibKScreen is present */ +#define HAVE_LIBKSCREEN ${LibKScreen_FOUND} diff --git a/core/document.cpp b/core/document.cpp index fa6345feb..19eaa70e1 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -84,6 +84,7 @@ #include "view.h" #include "view_p.h" #include "form.h" +#include "utils.h" #include @@ -267,6 +268,14 @@ QString DocumentPrivate::localizedSize(const QSizeF &size) const inchesHeight = size.height() / 72.0; break; + case Generator::Pixels: + { + const QSizeF dpi = m_generator->dpi(); + inchesWidth = size.width() / dpi.width(); + inchesHeight = size.height() / dpi.height(); + } + break; + case Generator::None: break; } @@ -917,6 +926,9 @@ bool DocumentPrivate::openDocumentInternal( const KService::Ptr& offer, bool iss QObject::connect( m_generator, SIGNAL(notice(QString,int)), m_parent, SIGNAL(notice(QString,int)) ); QApplication::setOverrideCursor( Qt::WaitCursor ); + + m_generator->setDPI(Utils::realDpi(m_widget)); + bool openOk = false; if ( !isstdin ) { diff --git a/core/generator.cpp b/core/generator.cpp index 41beb92b7..23b274b1d 100644 --- a/core/generator.cpp +++ b/core/generator.cpp @@ -31,7 +31,8 @@ GeneratorPrivate::GeneratorPrivate() : m_document( 0 ), mPixmapGenerationThread( 0 ), mTextPageGenerationThread( 0 ), m_mutex( 0 ), m_threadsMutex( 0 ), mPixmapReady( true ), mTextPageReady( true ), - m_closing( false ), m_closingLoop( 0 ) + m_closing( false ), m_closingLoop( 0 ), + m_dpi(72.0, 72.0) { } @@ -422,6 +423,18 @@ const SourceReference * Generator::dynamicSourceReference( int /*pageNr*/, doubl return 0; } +void Generator::setDPI(const QSizeF & dpi) +{ + Q_D( Generator ); + d->m_dpi = dpi; +} + +QSizeF Generator::dpi() const +{ + Q_D( const Generator ); + return d->m_dpi; +} + PixmapRequest::PixmapRequest( DocumentObserver *observer, int pageNumber, int width, int height, int priority, PixmapRequestFeatures features ) : d( new PixmapRequestPrivate ) { diff --git a/core/generator.h b/core/generator.h index 3cf40c2f2..19c81d51d 100644 --- a/core/generator.h +++ b/core/generator.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -308,7 +309,8 @@ class OKULAR_EXPORT Generator : public QObject enum PageSizeMetric { None, ///< The page size is not defined in a physical metric. - Points ///< The page size is given in 1/72 inches. + Points, ///< The page size is given in 1/72 inches. + Pixels ///< The page size is given in screen pixels @since 0.19 (KDE 4.13) }; /** @@ -384,6 +386,13 @@ class OKULAR_EXPORT Generator : public QObject */ bool hasFeature( GeneratorFeature feature ) const; + /** + * Update DPI of the generator + * + * @since 0.19 (KDE 4.13) + */ + void setDPI(const QSizeF &dpi); + Q_SIGNALS: /** * This signal should be emitted whenever an error occurred in the generator. @@ -476,6 +485,12 @@ class OKULAR_EXPORT Generator : public QObject */ void updatePageBoundingBox( int page, const NormalizedRect & boundingBox ); + /** + * Returns DPI, previously set via setDPI() + * @since 0.19 (KDE 4.13) + */ + QSizeF dpi() const; + protected Q_SLOTS: /** * Gets the font data for the given font diff --git a/core/generator_p.h b/core/generator_p.h index b59293a78..902176385 100644 --- a/core/generator_p.h +++ b/core/generator_p.h @@ -64,6 +64,7 @@ class GeneratorPrivate bool mTextPageReady : 1; bool m_closing : 1; QEventLoop *m_closingLoop; + QSizeF m_dpi; }; diff --git a/core/utils.cpp b/core/utils.cpp index 08923cf77..ac32ccce8 100644 --- a/core/utils.cpp +++ b/core/utils.cpp @@ -18,7 +18,11 @@ #include #ifdef Q_WS_X11 -#include + #include "config-okular.h" + #if HAVE_LIBKSCREEN + #include + #endif + #include #endif #ifdef Q_WS_MAC @@ -81,6 +85,48 @@ double Utils::realDpiY() return (double(w->height()) * 25.4) / double(w->heightMM()); } +QSizeF Utils::realDpi(QWidget* widgetOnScreen) +{ + // Firstly try to retrieve DPI via LibKScreen +#if HAVE_LIBKSCREEN + KScreen::Config* config = KScreen::Config::current(); + KScreen::OutputList outputs = config->outputs(); + QPoint globalPos = widgetOnScreen->parentWidget() ? + widgetOnScreen->mapToGlobal(widgetOnScreen->pos()): + widgetOnScreen->pos(); + QRect widgetRect(globalPos, widgetOnScreen->size()); + + KScreen::Output* selectedOutput = 0; + int maxArea = 0; + Q_FOREACH(KScreen::Output *output, outputs) { + if (output->currentMode()) { + QRect outputRect(output->pos(),output->currentMode()->size()); + QRect intersection = outputRect.intersected(widgetRect); + int area = intersection.width()*intersection.height(); + if (area > maxArea) { + maxArea = area; + selectedOutput = output; + } + } + } + + if (selectedOutput) { + kDebug() << "Found widget at output #" << selectedOutput->id(); + QRect outputRect(selectedOutput->pos(),selectedOutput->currentMode()->size()); + QSize szMM = selectedOutput->sizeMm(); + QSizeF res(static_cast(outputRect.width())*25.4/szMM.width(), + static_cast(outputRect.height())*25.4/szMM.height()); + kDebug() << "Output DPI is " << res; + return res; + } +#endif + // this is also fallback for LibKScreen branch if KScreen::Output + // for particular widget was not found + const QDesktopWidget* desktop = QApplication::desktop(); + return QSizeF((desktop->width() * 25.4) / desktop->widthMM(), + (desktop->height() * 25.4) / desktop->heightMM()); +} + #elif defined(Q_WS_MAC) /* * Code copied from http://developer.apple.com/qa/qa2001/qa1217.html @@ -164,6 +210,11 @@ double Utils::realDpiY() { return dpiY(); } + +QSizeF Utils::realDpi(QWidget*) +{ + return QSizeF(realDpiX(), realDpiY()); +} #else double Utils::dpiX() @@ -185,6 +236,11 @@ double Utils::realDpiY() { return dpiY(); } + +QSizeF Utils::realDpi(QWidget*) +{ + return QSizeF(realDpiX(), realDpiY()); +} #endif inline static bool isWhite( QRgb argb ) { diff --git a/core/utils.h b/core/utils.h index 8d5d5fccb..dc490f7ca 100644 --- a/core/utils.h +++ b/core/utils.h @@ -15,6 +15,7 @@ class QRect; class QImage; +class QWidget; namespace Okular { @@ -50,6 +51,7 @@ class OKULAR_EXPORT Utils * setting. Otherwise, returns the same as dpiX(), * * @since 0.9 (KDE 4.3) + * @deprecated Can not work with multi-monitor configurations */ static double realDpiX(); @@ -60,9 +62,20 @@ class OKULAR_EXPORT Utils * setting. Otherwise, returns the same as dpiX(), * * @since 0.9 (KDE 4.3) + * @deprecated Can not work with multi-monitor configurations */ static double realDpiY(); + /** + * Return the real DPI of the display containing given widget + * + * On X11, it can indicate the real horizontal DPI value without any Xrdb + * setting. Otherwise, returns the same as realDpiX/Y(), + * + * @since 0.19 (KDE 4.13) + */ + static QSizeF realDpi(QWidget* widgetOnScreen); + /** * Compute the smallest rectangle that contains all non-white pixels in image), * in normalized [0,1] coordinates. @@ -75,3 +88,5 @@ class OKULAR_EXPORT Utils } #endif + +/* kate: replace-tabs on; indent-width 4; */ diff --git a/generators/poppler/generator_pdf.cpp b/generators/poppler/generator_pdf.cpp index 839a32414..f08a5714a 100644 --- a/generators/poppler/generator_pdf.cpp +++ b/generators/poppler/generator_pdf.cpp @@ -425,7 +425,6 @@ PDFGenerator::PDFGenerator( QObject *parent, const QVariantList &args ) : Generator( parent, args ), pdfdoc( 0 ), docInfoDirty( true ), docSynopsisDirty( true ), docEmbeddedFilesDirty( true ), nextFontPage( 0 ), - dpiX( 72.0 /*Okular::Utils::dpiX()*/ ), dpiY( 72.0 /*Okular::Utils::dpiY()*/ ), annotProxy( 0 ), synctex_scanner( 0 ) { setFeature( Threaded ); @@ -627,8 +626,8 @@ void PDFGenerator::loadPages(QVector &pagesVector, int rotation, if (p) { const QSizeF pSize = p->pageSizeF(); - w = pSize.width() / 72.0 * dpiX; - h = pSize.height() / 72.0 * dpiY; + w = pSize.width() / 72.0 * dpi().width(); + h = pSize.height() / 72.0 * dpi().height(); Okular::Rotation orientation = Okular::Rotation0; switch (p->orientation()) { @@ -908,8 +907,8 @@ QImage PDFGenerator::image( Okular::PixmapRequest * request ) if ( page->rotation() % 2 ) qSwap( pageWidth, pageHeight ); - double fakeDpiX = request->width() * dpiX / pageWidth, - fakeDpiY = request->height() * dpiY / pageHeight; + qreal fakeDpiX = request->width() / pageWidth * dpi().width(); + qreal fakeDpiY = request->height() / pageHeight * dpi().height(); // generate links rects only the first time bool genObjectRects = !rectsGenerated.at( page->number() ); @@ -1759,8 +1758,8 @@ void PDFGenerator::loadPdfSync( const QString & filePath, QVector // magic numbers for TeX's RSU's (Ridiculously Small Units) conversion to pixels Okular::NormalizedPoint p( - ( pt.x * dpiX ) / ( 72.27 * 65536.0 * pagesVector[pt.page]->width() ), - ( pt.y * dpiY ) / ( 72.27 * 65536.0 * pagesVector[pt.page]->height() ) + ( pt.x * dpi().width() ) / ( 72.27 * 65536.0 * pagesVector[pt.page]->width() ), + ( pt.y * dpi().height() ) / ( 72.27 * 65536.0 * pagesVector[pt.page]->height() ) ); QString file = pt.file; Okular::SourceReference * sourceRef = new Okular::SourceReference( file, pt.row, pt.column ); @@ -1781,7 +1780,7 @@ const Okular::SourceReference * PDFGenerator::dynamicSourceReference( int pageNr if ( !synctex_scanner ) return 0; - if (synctex_edit_query(synctex_scanner, pageNr + 1, absX * 72. / dpiX, absY * 72. / dpiY) > 0) + if (synctex_edit_query(synctex_scanner, pageNr + 1, absX * 72. / dpi().width(), absY * 72. / dpi().height()) > 0) { synctex_node_t node; // TODO what should we do if there is really more than one node? @@ -1852,8 +1851,8 @@ void PDFGenerator::fillViewportFromSourceReference( Okular::DocumentViewport & v if ( !viewport.isValid() ) return; // TeX small points ... - double px = (synctex_node_visible_h( node ) * dpiX) / 72.27; - double py = (synctex_node_visible_v( node ) * dpiY) / 72.27; + double px = (synctex_node_visible_h( node ) * dpi().width()) / 72.27; + double py = (synctex_node_visible_v( node ) * dpi().height()) / 72.27; viewport.rePos.normalizedX = px / document()->page(viewport.pageNumber)->width(); viewport.rePos.normalizedY = ( py + 0.5 ) / document()->page(viewport.pageNumber)->height(); viewport.rePos.enabled = true; diff --git a/generators/poppler/generator_pdf.h b/generators/poppler/generator_pdf.h index 5d5853ae7..eb91f665e 100644 --- a/generators/poppler/generator_pdf.h +++ b/generators/poppler/generator_pdf.h @@ -68,7 +68,7 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p const Okular::DocumentSynopsis * generateDocumentSynopsis(); Okular::FontInfo::List fontsForPage( int page ); const QList * embeddedFiles() const; - PageSizeMetric pagesSizeMetric() const { return Points; } + PageSizeMetric pagesSizeMetric() const { return Pixels; } // [INHERITED] document information bool isAllowed( Okular::Permission permission ) const; @@ -144,8 +144,6 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p mutable bool docEmbeddedFilesDirty; mutable QList docEmbeddedFiles; int nextFontPage; - double dpiX; - double dpiY; PopplerAnnotationProxy *annotProxy; QHash annotationsHash;