mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Issue #123: Alternative software rendering backend
This commit is contained in:
@ -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
|
||||
|
Reference in New Issue
Block a user