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:
@@ -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})
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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; }
|
||||
|
||||
|
Reference in New Issue
Block a user