Issue #123: Alternative software rendering backend

This commit is contained in:
Jakub Melka
2024-02-04 18:05:38 +01:00
parent 87cedf01dc
commit d314683d38
48 changed files with 872 additions and 761 deletions

View File

@@ -74,10 +74,6 @@ GENERATE_EXPORT_HEADER(Pdf4QtLibWidgets
PDF4QTLIBWIDGETSSHARED_EXPORT
EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR}/pdf4qtlibwidgets_export.h")
if(PDF4QT_ENABLE_OPENGL)
target_link_libraries(Pdf4QtLibWidgets PRIVATE Qt6::OpenGLWidgets)
endif()
target_link_libraries(Pdf4QtLibWidgets PRIVATE Pdf4QtLibCore Qt6::Core Qt6::Gui Qt6::Xml Qt6::Svg Qt6::Widgets)
if(LINUX_GCC)
@@ -88,6 +84,8 @@ if(MINGW)
target_link_libraries(Pdf4QtLibWidgets PRIVATE Secur32 Mscms Gdi32 User32 crypt32)
endif()
target_link_libraries(Pdf4QtLibWidgets PRIVATE blend2d::blend2d)
target_include_directories(Pdf4QtLibWidgets INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/sources)
target_include_directories(Pdf4QtLibWidgets PUBLIC ${CMAKE_BINARY_DIR}/${INSTALL_INCLUDEDIR})

View File

@@ -24,6 +24,7 @@
#include "pdfannotation.h"
#include "pdfdrawwidget.h"
#include "pdfwidgetannotation.h"
#include "pdfpainterutils.h"
#include <QTimer>
#include <QPainter>
@@ -31,6 +32,8 @@
#include <QScreen>
#include <QGuiApplication>
#include <Blend2d.h>
#include "pdfdbgheap.h"
namespace pdf
@@ -469,7 +472,7 @@ PDFDrawWidgetProxy::PDFDrawWidgetProxy(QObject* parent) :
m_rasterizer(new PDFRasterizer(this)),
m_progress(nullptr),
m_cacheClearTimer(new QTimer(this)),
m_useOpenGL(false)
m_rendererEngine(RendererEngine::Blend2D)
{
m_controller = new PDFDrawSpaceController(this);
connect(m_controller, &PDFDrawSpaceController::drawSpaceChanged, this, &PDFDrawWidgetProxy::update);
@@ -765,6 +768,18 @@ void PDFDrawWidgetProxy::draw(QPainter* painter, QRect rect)
}
}
void PDFDrawWidgetProxy::draw(BLContext& context, QRect rect)
{
drawPages(context, rect, m_features);
for (IDocumentDrawInterface* drawInterface : m_drawInterfaces)
{
context.save();
drawInterface->drawPostRendering(context, rect);
context.restore();
}
}
QColor PDFDrawWidgetProxy::getPaperColor()
{
QColor paperColor = getCMSManager()->getCurrentCMS()->getPaperColor();
@@ -920,6 +935,153 @@ void PDFDrawWidgetProxy::drawPages(QPainter* painter, QRect rect, PDFRenderer::F
}
}
void PDFDrawWidgetProxy::drawPages(BLContext& context, QRect rect, PDFRenderer::Features features)
{
PDFPainterHelper::setBLBrush(context, QBrush(Qt::lightGray));
context.fillRect(rect);
BLMatrix2D baseMatrix = context.userMatrix();
// Use current paper color (it can be a bit different from white)
QColor paperColor = getPaperColor();
// Iterate trough pages and display them on the painter device
for (const LayoutItem& item : m_layout.items)
{
// The offsets m_horizontalOffset and m_verticalOffset are offsets to the
// topleft point of the block. But block maybe doesn't start at (0, 0),
// so we must also use translation from the block beginning.
QRect placedRect = item.pageRect.translated(m_horizontalOffset - m_layout.blockRect.left(), m_verticalOffset - m_layout.blockRect.top());
if (placedRect.intersects(rect))
{
GroupInfo groupInfo = getGroupInfo(item.groupIndex);
// Clear the page space by paper color
if (groupInfo.drawPaper)
{
PDFPainterHelper::setBLBrush(context, paperColor);
context.fillRect(placedRect);
}
const PDFPrecompiledPage* compiledPage = m_compiler->getCompiledPage(item.pageIndex, true);
if (compiledPage && compiledPage->isValid())
{
QElapsedTimer timer;
timer.start();
const PDFPage* page = m_controller->getDocument()->getCatalog()->getPage(item.pageIndex);
QTransform matrix = QTransform(createPagePointToDevicePointMatrix(page, placedRect)) * baseMatrix;
compiledPage->draw(context, page->getCropBox(), matrix, features, groupInfo.transparency);
PDFTextLayoutGetter layoutGetter = m_textLayoutCompiler->getTextLayoutLazy(item.pageIndex);
// Draw text blocks/text lines, if it is enabled
if (features.testFlag(PDFRenderer::DebugTextBlocks))
{
m_textLayoutCompiler->makeTextLayout();
const PDFTextLayout& layout = layoutGetter;
const PDFTextBlocks& textBlocks = layout.getTextBlocks();
context.save();
painter->setFont(m_widget->font());
painter->setPen(Qt::red);
painter->setBrush(QColor(255, 0, 0, 128));
QFontMetricsF fontMetrics(painter->font(), painter->device());
int blockIndex = 1;
for (const PDFTextBlock& block : textBlocks)
{
QString blockNumber = QString::number(blockIndex++);
painter->drawPath(matrix.map(block.getBoundingBox()));
painter->drawText(matrix.map(block.getTopLeft()) - QPointF(fontMetrics.horizontalAdvance(blockNumber), 0), blockNumber, Qt::TextSingleLine, 0);
}
context.restore();
}
if (features.testFlag(PDFRenderer::DebugTextLines))
{
m_textLayoutCompiler->makeTextLayout();
const PDFTextLayout& layout = layoutGetter;
const PDFTextBlocks& textBlocks = layout.getTextBlocks();
context.save();
painter->setFont(m_widget->font());
painter->setPen(Qt::green);
painter->setBrush(QColor(0, 255, 0, 128));
QFontMetricsF fontMetrics(painter->font(), painter->device());
int lineIndex = 1;
for (const PDFTextBlock& block : textBlocks)
{
for (const PDFTextLine& line : block.getLines())
{
QString lineNumber = QString::number(lineIndex++);
painter->drawPath(matrix.map(line.getBoundingBox()));
painter->drawText(matrix.map(line.getTopLeft()) - QPointF(fontMetrics.horizontalAdvance(lineNumber), 0), lineNumber, Qt::TextSingleLine, 0);
}
}
context.restore();
}
QList<PDFRenderError> drawInterfaceErrors;
if (!features.testFlag(PDFRenderer::DenyExtraGraphics))
{
for (IDocumentDrawInterface* drawInterface : m_drawInterfaces)
{
context.save();
drawInterface->drawPage(context, item.pageIndex, compiledPage, layoutGetter, matrix, drawInterfaceErrors);
context.restore();
}
}
const qint64 drawTimeNS = timer.nsecsElapsed();
// Draw rendering times
if (features.testFlag(PDFRenderer::DisplayTimes))
{
QFont font = m_widget->font();
font.setPointSize(12);
auto formatDrawTime = [](qint64 nanoseconds)
{
PDFReal miliseconds = nanoseconds / 1000000.0;
return QString::number(miliseconds, 'f', 3);
};
QFontMetrics fontMetrics(font);
const int lineSpacing = fontMetrics.lineSpacing();
context.save();
painter->setPen(Qt::red);
painter->setFont(font);
context.translate(placedRect.topLeft());
context.translate(placedRect.width() / 20.0, placedRect.height() / 20.0); // Offset
painter->setBackground(QBrush(Qt::white));
painter->setBackgroundMode(Qt::OpaqueMode);
painter->drawText(0, 0, PDFTranslationContext::tr("Compile time: %1 [ms]").arg(formatDrawTime(compiledPage->getCompilingTimeNS())));
painter->translate(0, lineSpacing);
painter->drawText(0, 0, PDFTranslationContext::tr("Draw time: %1 [ms]").arg(formatDrawTime(drawTimeNS)));
context.restore();
}
const QList<PDFRenderError>& pageErrors = compiledPage->getErrors();
if (!pageErrors.empty() || !drawInterfaceErrors.empty())
{
QList<PDFRenderError> errors = pageErrors;
if (!drawInterfaceErrors.isEmpty())
{
errors.append(drawInterfaceErrors);
}
Q_EMIT renderingError(item.pageIndex, qMove(errors));
}
}
}
}
}
QImage PDFDrawWidgetProxy::drawThumbnailImage(PDFInteger pageIndex, int pixelSize) const
{
QImage image;
@@ -1403,11 +1565,10 @@ bool PDFDrawWidgetProxy::isBlockMode() const
return false;
}
void PDFDrawWidgetProxy::updateRenderer(bool useOpenGL, const QSurfaceFormat& surfaceFormat)
void PDFDrawWidgetProxy::updateRenderer(RendererEngine rendererEngine)
{
m_useOpenGL = useOpenGL;
m_surfaceFormat = surfaceFormat;
m_rasterizer->reset(useOpenGL && ENABLE_OPENGL_FOR_THUMBNAILS, surfaceFormat);
m_rendererEngine = rendererEngine;
m_rasterizer->reset(m_rendererEngine);
}
void PDFDrawWidgetProxy::prefetchPages(PDFInteger pageIndex)

View File

@@ -34,6 +34,8 @@ class QPainter;
class QScrollBar;
class QTimer;
class BLContext;
namespace pdf
{
class PDFProgress;
@@ -212,6 +214,15 @@ public:
/// \param rect Rectangle in which the content is painted
void draw(QPainter* painter, QRect rect);
/// Draws the actually visible pages on the context using the rectangle.
/// Rectangle is space in the widget, which is used for painting the PDF.
/// This function is using drawPages function to draw all pages. After that,
/// custom drawing is performed.
/// \sa drawPages
/// \param context Context to paint the PDF pages
/// \param rect Rectangle in which the content is painted
void draw(BLContext& context, QRect rect);
/// Draws the actually visible pages on the painter using the rectangle.
/// Rectangle is space in the widget, which is used for painting the PDF.
/// \param painter Painter to paint the PDF pages
@@ -219,6 +230,13 @@ public:
/// \param features Rendering features
void drawPages(QPainter* painter, QRect rect, PDFRenderer::Features features);
/// Draws the actually visible pages on the painter using the rectangle.
/// Rectangle is space in the widget, which is used for painting the PDF.
/// \param painter Painter to paint the PDF pages
/// \param rect Rectangle in which the content is painted
/// \param features Rendering features
void drawPages(BLContext& context, QRect rect, PDFRenderer::Features features);
/// Draws thumbnail image of the given size (so larger of the page size
/// width or height equals to pixel size and the latter size is rescaled
/// using the aspect ratio)
@@ -317,9 +335,8 @@ public:
/// Updates renderer (in current implementation, renderer for page thumbnails)
/// using given parameters.
/// \param useOpenGL Use OpenGL for rendering?
/// \param surfaceFormat Surface format for OpenGL rendering
void updateRenderer(bool useOpenGL, const QSurfaceFormat& surfaceFormat);
/// \param rendererEngine Renderer engine
void updateRenderer(RendererEngine rendererEngine);
/// Prefetches (prerenders) pages after page with pageIndex, i.e., prepares
/// for non-flickering scroll operation.
@@ -338,8 +355,7 @@ public:
void setProgress(PDFProgress* progress) { m_progress = progress; }
PDFAsynchronousTextLayoutCompiler* getTextLayoutCompiler() const { return m_textLayoutCompiler; }
PDFWidget* getWidget() const { return m_widget; }
bool isUsingOpenGL() const { return m_useOpenGL; }
const QSurfaceFormat& getSurfaceFormat() const { return m_surfaceFormat; }
RendererEngine getRendererEngine() const { return m_rendererEngine; }
PageRotation getPageRotation() const { return m_controller->getPageRotation(); }
void setFeatures(PDFRenderer::Features features);
@@ -461,8 +477,6 @@ private:
constexpr inline T bound(T value) { return qBound(min, value, max); }
};
static constexpr bool ENABLE_OPENGL_FOR_THUMBNAILS = false;
/// Flag, disables the update
bool m_updateDisabled;
@@ -536,11 +550,8 @@ private:
/// Additional drawing interfaces
std::set<IDocumentDrawInterface*> m_drawInterfaces;
/// Use OpenGL for rendering?
bool m_useOpenGL;
/// Surface format for OpenGL
QSurfaceFormat m_surfaceFormat;
/// Renderer engine
RendererEngine m_rendererEngine;
/// Page group info for rendering. Group of pages
/// can be rendered with transparency or without paper

View File

@@ -30,12 +30,14 @@
#include <QPixmapCache>
#include <QColorSpace>
#include <Blend2d.h>
#include "pdfdbgheap.h"
namespace pdf
{
PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int samplesCount, QWidget* parent) :
PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, QWidget* parent) :
QWidget(parent),
m_cmsManager(cmsManager),
m_toolManager(nullptr),
@@ -44,9 +46,10 @@ PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int
m_drawWidget(nullptr),
m_horizontalScrollBar(nullptr),
m_verticalScrollBar(nullptr),
m_proxy(nullptr)
m_proxy(nullptr),
m_rendererEngine(engine)
{
m_drawWidget = createDrawWidget(getEffectiveRenderer(engine), samplesCount);
m_drawWidget = new PDFDrawWidget(this, this);
m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this);
m_verticalScrollBar = new QScrollBar(Qt::Vertical, this);
@@ -62,10 +65,10 @@ PDFWidget::PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int
m_proxy = new PDFDrawWidgetProxy(this);
m_proxy->init(this);
m_proxy->updateRenderer(m_rendererEngine);
connect(m_proxy, &PDFDrawWidgetProxy::renderingError, this, &PDFWidget::onRenderingError);
connect(m_proxy, &PDFDrawWidgetProxy::repaintNeeded, m_drawWidget->getWidget(), QOverload<>::of(&QWidget::update));
connect(m_proxy, &PDFDrawWidgetProxy::pageImageChanged, this, &PDFWidget::onPageImageChanged);
updateRendererImpl();
}
PDFWidget::~PDFWidget()
@@ -90,39 +93,10 @@ void PDFWidget::setDocument(const PDFModifiedDocument& document)
m_drawWidget->getWidget()->update();
}
void PDFWidget::updateRenderer(RendererEngine engine, int samplesCount)
void PDFWidget::updateRenderer(RendererEngine engine)
{
engine = getEffectiveRenderer(engine);
PDFOpenGLDrawWidget* openglDrawWidget = qobject_cast<PDFOpenGLDrawWidget*>(m_drawWidget->getWidget());
PDFDrawWidget* softwareDrawWidget = qobject_cast<PDFDrawWidget*>(m_drawWidget->getWidget());
// Do we need to change renderer?
if ((openglDrawWidget && engine != RendererEngine::OpenGL) || (softwareDrawWidget && engine != RendererEngine::Software))
{
QGridLayout* layout = qobject_cast<QGridLayout*>(this->layout());
layout->removeWidget(m_drawWidget->getWidget());
delete m_drawWidget->getWidget();
m_drawWidget = createDrawWidget(engine, samplesCount);
layout->addWidget(m_drawWidget->getWidget(), 0, 0);
setFocusProxy(m_drawWidget->getWidget());
connect(m_proxy, &PDFDrawWidgetProxy::repaintNeeded, m_drawWidget->getWidget(), QOverload<>::of(&QWidget::update));
}
#ifdef PDF4QT_ENABLE_OPENGL
else if (openglDrawWidget)
{
// Just check the samples count
QSurfaceFormat format = openglDrawWidget->format();
if (format.samples() != samplesCount)
{
format.setSamples(samplesCount);
openglDrawWidget->setFormat(format);
}
}
#endif
updateRendererImpl();
m_rendererEngine = engine;
m_proxy->updateRenderer(m_rendererEngine);
}
void PDFWidget::updateCacheLimits(int compiledPageCacheLimit, int thumbnailsCacheLimit, int fontCacheLimit, int instancedFontCacheLimit)
@@ -142,16 +116,6 @@ int PDFWidget::getPageRenderingErrorCount() const
return count;
}
void PDFWidget::updateRendererImpl()
{
#ifdef PDF4QT_ENABLE_OPENGL
PDFOpenGLDrawWidget* openglDrawWidget = qobject_cast<PDFOpenGLDrawWidget*>(m_drawWidget->getWidget());
m_proxy->updateRenderer(openglDrawWidget != nullptr, openglDrawWidget ? openglDrawWidget->format() : QSurfaceFormat::defaultFormat());
#else
m_proxy->updateRenderer(false, QSurfaceFormat::defaultFormat());
#endif
}
void PDFWidget::onRenderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors)
{
// Empty list of error should not be reported!
@@ -182,29 +146,6 @@ void PDFWidget::onPageImageChanged(bool all, const std::vector<PDFInteger>& page
}
}
IDrawWidget* PDFWidget::createDrawWidget(RendererEngine rendererEngine, int samplesCount)
{
switch (rendererEngine)
{
case RendererEngine::Software:
return new PDFDrawWidget(this, this);
case RendererEngine::OpenGL:
#ifdef PDF4QT_ENABLE_OPENGL
return new PDFOpenGLDrawWidget(this, samplesCount, this);
#else
Q_UNUSED(samplesCount);
return new PDFDrawWidget(this, this);
#endif
default:
Q_ASSERT(false);
break;
}
return nullptr;
}
void PDFWidget::removeInputInterface(IDrawWidgetInputInterface* inputInterface)
{
auto it = std::find(m_inputInterfaces.begin(), m_inputInterfaces.end(), inputInterface);
@@ -223,16 +164,6 @@ void PDFWidget::addInputInterface(IDrawWidgetInputInterface* inputInterface)
}
}
RendererEngine PDFWidget::getEffectiveRenderer(RendererEngine rendererEngine)
{
if (rendererEngine == RendererEngine::OpenGL && !pdf::PDFRendererInfo::isHardwareAccelerationSupported())
{
return RendererEngine::Software;
}
return rendererEngine;
}
PDFWidgetFormManager* PDFWidget::getFormManager() const
{
return m_formManager;
@@ -259,43 +190,38 @@ void PDFWidget::setAnnotationManager(PDFWidgetAnnotationManager* annotationManag
addInputInterface(m_annotationManager);
}
template<typename BaseWidget>
PDFDrawWidgetBase<BaseWidget>::PDFDrawWidgetBase(PDFWidget* widget, QWidget* parent) :
BaseWidget(parent),
PDFDrawWidget::PDFDrawWidget(PDFWidget* widget, QWidget* parent) :
BaseClass(parent),
m_widget(widget),
m_mouseOperation(MouseOperation::None)
{
this->setFocusPolicy(Qt::StrongFocus);
this->setMouseTracking(true);
QObject::connect(&m_autoScrollTimer, &QTimer::timeout, this, &PDFDrawWidgetBase::onAutoScrollTimeout);
QObject::connect(&m_autoScrollTimer, &QTimer::timeout, this, &PDFDrawWidget::onAutoScrollTimeout);
}
template<typename BaseWidget>
std::vector<PDFInteger> PDFDrawWidgetBase<BaseWidget>::getCurrentPages() const
std::vector<PDFInteger> PDFDrawWidget::getCurrentPages() const
{
return this->m_widget->getDrawWidgetProxy()->getPagesIntersectingRect(this->rect());
}
template<typename BaseWidget>
QSize PDFDrawWidgetBase<BaseWidget>::minimumSizeHint() const
QSize PDFDrawWidget::minimumSizeHint() const
{
return QSize(200, 200);
}
template<typename BaseWidget>
bool PDFDrawWidgetBase<BaseWidget>::event(QEvent* event)
bool PDFDrawWidget::event(QEvent* event)
{
if (event->type() == QEvent::ShortcutOverride)
{
return processEvent<QKeyEvent, &IDrawWidgetInputInterface::shortcutOverrideEvent>(static_cast<QKeyEvent*>(event));
}
return BaseWidget::event(event);
return BaseClass::event(event);
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::performMouseOperation(QPoint currentMousePosition)
void PDFDrawWidget::performMouseOperation(QPoint currentMousePosition)
{
switch (m_mouseOperation)
{
@@ -323,9 +249,8 @@ void PDFDrawWidgetBase<BaseWidget>::performMouseOperation(QPoint currentMousePos
}
}
template<typename BaseWidget>
template<typename Event, void (IDrawWidgetInputInterface::* Function)(QWidget*, Event*)>
bool PDFDrawWidgetBase<BaseWidget>::processEvent(Event* event)
bool PDFDrawWidget::processEvent(Event* event)
{
QString tooltip;
for (IDrawWidgetInputInterface* inputInterface : m_widget->getInputInterfaces())
@@ -351,8 +276,7 @@ bool PDFDrawWidgetBase<BaseWidget>::processEvent(Event* event)
return false;
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::keyPressEvent(QKeyEvent* event)
void PDFDrawWidget::keyPressEvent(QKeyEvent* event)
{
event->ignore();
@@ -388,8 +312,7 @@ void PDFDrawWidgetBase<BaseWidget>::keyPressEvent(QKeyEvent* event)
updateCursor();
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::keyReleaseEvent(QKeyEvent* event)
void PDFDrawWidget::keyReleaseEvent(QKeyEvent* event)
{
event->ignore();
@@ -401,8 +324,7 @@ void PDFDrawWidgetBase<BaseWidget>::keyReleaseEvent(QKeyEvent* event)
event->accept();
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::mousePressEvent(QMouseEvent* event)
void PDFDrawWidget::mousePressEvent(QMouseEvent* event)
{
event->ignore();
@@ -442,8 +364,7 @@ void PDFDrawWidgetBase<BaseWidget>::mousePressEvent(QMouseEvent* event)
event->accept();
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::mouseDoubleClickEvent(QMouseEvent* event)
void PDFDrawWidget::mouseDoubleClickEvent(QMouseEvent* event)
{
event->ignore();
@@ -453,8 +374,7 @@ void PDFDrawWidgetBase<BaseWidget>::mouseDoubleClickEvent(QMouseEvent* event)
}
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::mouseReleaseEvent(QMouseEvent* event)
void PDFDrawWidget::mouseReleaseEvent(QMouseEvent* event)
{
event->ignore();
@@ -491,8 +411,7 @@ void PDFDrawWidgetBase<BaseWidget>::mouseReleaseEvent(QMouseEvent* event)
event->accept();
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::mouseMoveEvent(QMouseEvent* event)
void PDFDrawWidget::mouseMoveEvent(QMouseEvent* event)
{
event->ignore();
@@ -506,8 +425,7 @@ void PDFDrawWidgetBase<BaseWidget>::mouseMoveEvent(QMouseEvent* event)
event->accept();
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::updateCursor()
void PDFDrawWidget::updateCursor()
{
std::optional<QCursor> cursor;
@@ -554,8 +472,7 @@ void PDFDrawWidgetBase<BaseWidget>::updateCursor()
}
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::onAutoScrollTimeout()
void PDFDrawWidget::onAutoScrollTimeout()
{
if (m_mouseOperation != MouseOperation::AutoScroll)
{
@@ -579,8 +496,7 @@ void PDFDrawWidgetBase<BaseWidget>::onAutoScrollTimeout()
proxy->scrollByPixels(QPoint(scrollX, scrollY));
}
template<typename BaseWidget>
void PDFDrawWidgetBase<BaseWidget>::wheelEvent(QWheelEvent* event)
void PDFDrawWidget::wheelEvent(QWheelEvent* event)
{
event->ignore();
@@ -659,62 +575,56 @@ void PDFDrawWidgetBase<BaseWidget>::wheelEvent(QWheelEvent* event)
event->accept();
}
#ifdef PDF4QT_ENABLE_OPENGL
PDFOpenGLDrawWidget::PDFOpenGLDrawWidget(PDFWidget* widget, int samplesCount, QWidget* parent) :
BaseClass(widget, parent)
{
QSurfaceFormat format = this->format();
format.setProfile(QSurfaceFormat::CoreProfile);
format.setSamples(samplesCount);
format.setColorSpace(QColorSpace(QColorSpace::SRgb));
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
setFormat(format);
}
PDFOpenGLDrawWidget::~PDFOpenGLDrawWidget()
{
}
void PDFOpenGLDrawWidget::resizeGL(int w, int h)
{
QOpenGLWidget::resizeGL(w, h);
getPDFWidget()->getDrawWidgetProxy()->update();
}
void PDFOpenGLDrawWidget::initializeGL()
{
QOpenGLWidget::initializeGL();
}
void PDFOpenGLDrawWidget::paintGL()
{
if (this->isValid())
{
QPainter painter(this);
getPDFWidget()->getDrawWidgetProxy()->draw(&painter, this->rect());
}
}
#endif
PDFDrawWidget::PDFDrawWidget(PDFWidget* widget, QWidget* parent) :
BaseClass(widget, parent)
{
}
PDFDrawWidget::~PDFDrawWidget()
{
}
void PDFDrawWidget::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
QPainter painter(this);
getPDFWidget()->getDrawWidgetProxy()->draw(&painter, this->rect());
switch (getPDFWidget()->getDrawWidgetProxy()->getRendererEngine())
{
case RendererEngine::Blend2D:
{
BLContext blContext;
BLImage blImage;
QRect rect = this->rect();
if (m_blend2DframeBuffer.size() != rect.size())
{
m_blend2DframeBuffer = QImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
}
BLContextCreateInfo info{};
info.reset();
info.flags = BL_CONTEXT_CREATE_FLAG_FALLBACK_TO_SYNC;
info.threadCount = QThread::idealThreadCount();
blContext.setHint(BL_CONTEXT_HINT_RENDERING_QUALITY, BL_RENDERING_QUALITY_MAX_VALUE);
blImage.createFromData(m_blend2DframeBuffer.width(), m_blend2DframeBuffer.height(), BL_FORMAT_PRGB32, m_blend2DframeBuffer.bits(), m_blend2DframeBuffer.bytesPerLine());
if (blContext.begin(blImage, info) == BL_SUCCESS)
{
blContext.clearAll();
getPDFWidget()->getDrawWidgetProxy()->draw(blContext, rect);
blContext.end();
QPainter painter(this);
painter.drawImage(QPoint(0, 0), m_blend2DframeBuffer);
}
break;
}
case RendererEngine::QPainter:
{
QPainter painter(this);
getPDFWidget()->getDrawWidgetProxy()->draw(&painter, this->rect());
m_blend2DframeBuffer = QImage();
break;
}
default:
Q_ASSERT(false);
break;
}
}
void PDFDrawWidget::resizeEvent(QResizeEvent* event)
@@ -724,9 +634,4 @@ void PDFDrawWidget::resizeEvent(QResizeEvent* event)
getPDFWidget()->getDrawWidgetProxy()->update();
}
#ifdef PDF4QT_ENABLE_OPENGL
template class PDFDrawWidgetBase<QOpenGLWidget>;
#endif
template class PDFDrawWidgetBase<QWidget>;
} // namespace pdf

View File

@@ -27,10 +27,6 @@
#include <QTimer>
#include <QElapsedTimer>
#ifdef PDF4QT_ENABLE_OPENGL
#include <QOpenGLWidget>
#endif
namespace pdf
{
class PDFDocument;
@@ -65,8 +61,7 @@ public:
/// Constructs new PDFWidget.
/// \param cmsManager Color management system manager
/// \param engine Rendering engine type
/// \param samplesCount Samples count for rendering engine MSAA antialiasing
explicit PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, int samplesCount, QWidget* parent);
explicit PDFWidget(const PDFCMSManager* cmsManager, RendererEngine engine, QWidget* parent);
virtual ~PDFWidget() override;
virtual bool focusNextPrevChild(bool next) override;
@@ -81,8 +76,7 @@ public:
/// Update rendering engine according the settings
/// \param engine Engine type
/// \param samplesCount Samples count for rendering engine MSAA antialiasing
void updateRenderer(RendererEngine engine, int samplesCount);
void updateRenderer(RendererEngine engine);
/// Updates cache limits
/// \param compiledPageCacheLimit Compiled page cache limit [bytes]
@@ -115,14 +109,9 @@ signals:
void pageRenderingErrorsChanged(pdf::PDFInteger pageIndex, int errorsCount);
private:
RendererEngine getEffectiveRenderer(RendererEngine rendererEngine);
void updateRendererImpl();
void onRenderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors);
void onPageImageChanged(bool all, const std::vector<PDFInteger>& pages);
IDrawWidget* createDrawWidget(RendererEngine rendererEngine, int samplesCount);
const PDFCMSManager* m_cmsManager;
PDFToolManager* m_toolManager;
PDFWidgetAnnotationManager* m_annotationManager;
@@ -133,14 +122,19 @@ private:
PDFDrawWidgetProxy* m_proxy;
PageRenderingErrors m_pageRenderingErrors;
std::vector<IDrawWidgetInputInterface*> m_inputInterfaces;
RendererEngine m_rendererEngine;
};
template<typename BaseWidget>
class PDFDrawWidgetBase : public BaseWidget, public IDrawWidget
class PDFDrawWidget : public QWidget, public IDrawWidget
{
Q_OBJECT
private:
using BaseClass = QWidget;
public:
explicit PDFDrawWidgetBase(PDFWidget* widget, QWidget* parent);
virtual ~PDFDrawWidgetBase() override = default;
explicit PDFDrawWidget(PDFWidget* widget, QWidget* parent);
virtual ~PDFDrawWidget() override = default;
/// Returns page indices, which are currently displayed in the widget
virtual std::vector<PDFInteger> getCurrentPages() const override;
@@ -158,6 +152,8 @@ protected:
virtual void mouseReleaseEvent(QMouseEvent* event) override;
virtual void mouseMoveEvent(QMouseEvent* event) override;
virtual void wheelEvent(QWheelEvent* event) override;
virtual void paintEvent(QPaintEvent* event) override;
virtual void resizeEvent(QResizeEvent* event) override;
PDFWidget* getPDFWidget() const { return m_widget; }
@@ -186,50 +182,9 @@ private:
QTimer m_autoScrollTimer;
QPointF m_autoScrollOffset;
QElapsedTimer m_autoScrollLastElapsedTimer;
QImage m_blend2DframeBuffer;
};
class PDFDrawWidget : public PDFDrawWidgetBase<QWidget>
{
Q_OBJECT
private:
using BaseClass = PDFDrawWidgetBase<QWidget>;
public:
explicit PDFDrawWidget(PDFWidget* widget, QWidget* parent);
virtual ~PDFDrawWidget() override;
protected:
virtual void paintEvent(QPaintEvent* event) override;
virtual void resizeEvent(QResizeEvent* event) override;
};
#ifdef PDF4QT_ENABLE_OPENGL
class PDFOpenGLDrawWidget : public PDFDrawWidgetBase<QOpenGLWidget>
{
Q_OBJECT
private:
using BaseClass = PDFDrawWidgetBase<QOpenGLWidget>;
public:
explicit PDFOpenGLDrawWidget(PDFWidget* widget, int samplesCount, QWidget* parent);
virtual ~PDFOpenGLDrawWidget() override;
protected:
virtual void resizeGL(int w, int h) override;
virtual void initializeGL() override;
virtual void paintGL() override;
};
#else
using PDFOpenGLDrawWidget = PDFDrawWidget;
#endif
#ifdef PDF4QT_ENABLE_OPENGL
extern template class PDFDrawWidgetBase<QOpenGLWidget>;
#endif
extern template class PDFDrawWidgetBase<QWidget>;
} // namespace pdf
#endif // PDFDRAWWIDGET_H

View File

@@ -539,4 +539,9 @@ void PDFWidgetAnnotationManager::drawPage(QPainter* painter,
BaseClass::drawPage(painter, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
}
void PDFWidgetAnnotationManager::drawPage(BLContext& context, PDFInteger pageIndex, const PDFPrecompiledPage* compiledPage, PDFTextLayoutGetter& layoutGetter, const QTransform& pagePointToDevicePointMatrix, QList<PDFRenderError>& errors) const
{
BaseClass::drawPage(context, pageIndex, compiledPage, layoutGetter, pagePointToDevicePointMatrix, errors);
}
} // namespace pdf

View File

@@ -57,6 +57,13 @@ public:
const QTransform& pagePointToDevicePointMatrix,
QList<PDFRenderError>& errors) const override;
virtual void drawPage(BLContext& context,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QTransform& pagePointToDevicePointMatrix,
QList<PDFRenderError>& errors) const override;
/// Returns tooltip generated from annotation
virtual QString getTooltip() const override { return m_tooltip; }