From 0447b9e3a1214775c07e33062b2aa6b439c14890 Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Sat, 4 May 2019 18:22:40 +0200 Subject: [PATCH] Minor bugfixes --- .../sources/pdfdrawspacecontroller.cpp | 29 ++++++++++++++- PdfForQtLib/sources/pdfdrawspacecontroller.h | 16 +++++--- PdfForQtLib/sources/pdfdrawwidget.cpp | 37 +++++++++++++++++-- .../sources/pdfpagecontentprocessor.cpp | 21 ++++++----- PdfForQtLib/sources/pdfpagecontentprocessor.h | 3 +- PdfForQtLib/sources/pdfpainter.cpp | 6 ++- PdfForQtLib/sources/pdfpainter.h | 2 +- PdfForQtLib/sources/pdfrenderer.cpp | 3 +- 8 files changed, 90 insertions(+), 27 deletions(-) diff --git a/PdfForQtLib/sources/pdfdrawspacecontroller.cpp b/PdfForQtLib/sources/pdfdrawspacecontroller.cpp index fdc3622..a5c9152 100644 --- a/PdfForQtLib/sources/pdfdrawspacecontroller.cpp +++ b/PdfForQtLib/sources/pdfdrawspacecontroller.cpp @@ -408,7 +408,7 @@ void PDFDrawWidgetProxy::update() } else { - m_currentBlock = qBound(0, m_currentBlock, m_controller->getBlockCount()); + m_currentBlock = qBound(0, m_currentBlock, m_controller->getBlockCount() - 1); } } else @@ -579,6 +579,26 @@ std::vector PDFDrawWidgetProxy::getPagesIntersectingRect(QRect rect) return pages; } +QRect PDFDrawWidgetProxy::getPagesIntersectingRectBoundingBox(QRect rect) const +{ + QRect resultRect; + + // Iterate trough pages, place them and test, if they intersects with rectangle + 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)) + { + resultRect = resultRect.united(placedRect); + } + } + + return resultRect; +} + void PDFDrawWidgetProxy::performOperation(Operation operation) { switch (operation) @@ -645,10 +665,15 @@ void PDFDrawWidgetProxy::performOperation(Operation operation) } } -void PDFDrawWidgetProxy::scrollByPixels(QPoint offset) +QPoint PDFDrawWidgetProxy::scrollByPixels(QPoint offset) { + PDFInteger oldHorizontalOffset = m_horizontalOffset; + PDFInteger oldVerticalOffset = m_verticalOffset; + setHorizontalOffset(m_horizontalOffset + offset.x()); setVerticalOffset(m_verticalOffset + offset.y()); + + return QPoint(m_horizontalOffset - oldHorizontalOffset, m_verticalOffset - oldVerticalOffset); } void PDFDrawWidgetProxy::zoom(PDFReal zoom) diff --git a/PdfForQtLib/sources/pdfdrawspacecontroller.h b/PdfForQtLib/sources/pdfdrawspacecontroller.h index 6f0ce20..32b4d1d 100644 --- a/PdfForQtLib/sources/pdfdrawspacecontroller.h +++ b/PdfForQtLib/sources/pdfdrawspacecontroller.h @@ -170,9 +170,9 @@ public: void performOperation(Operation operation); /// Scrolls by pixels, if it is possible. If it is not possible to scroll, - /// then nothing happens. + /// then nothing happens. Returns pixel offset, by which view camera was moved. /// \param offset Offset in pixels - void scrollByPixels(QPoint offset); + QPoint scrollByPixels(QPoint offset); /// Sets the zoom. Tries to preserve current offsets (so the current visible /// area will be visible after the zoom). @@ -194,6 +194,14 @@ public: /// \param rect Rectangle to test std::vector getPagesIntersectingRect(QRect rect) const; + /// Returns bounding box of pages, which are intersecting rectangle (even partially) + /// \param rect Rectangle to test + QRect getPagesIntersectingRectBoundingBox(QRect rect) const; + + /// Returns true, if we are in the block mode (multiple blocks with separate pages), + /// or continuous mode (single block with continuous list of separated pages). + bool isBlockMode() const; + static constexpr PDFReal ZOOM_STEP = 1.2; signals: @@ -237,10 +245,6 @@ private: /// Converts rectangle from device space to the pixel space QRectF fromDeviceSpace(const QRectF& rect) const; - /// Returns true, if we are in the block mode (multiple blocks with separate pages), - /// or continuous mode (single block with continuous list of separated pages). - bool isBlockMode() const; - void onHorizontalScrollbarValueChanged(int value); void onVerticalScrollbarValueChanged(int value); diff --git a/PdfForQtLib/sources/pdfdrawwidget.cpp b/PdfForQtLib/sources/pdfdrawwidget.cpp index e1603d5..417a5cf 100644 --- a/PdfForQtLib/sources/pdfdrawwidget.cpp +++ b/PdfForQtLib/sources/pdfdrawwidget.cpp @@ -193,6 +193,7 @@ void PDFDrawWidget::wheelEvent(QWheelEvent* event) { Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers(); + PDFDrawWidgetProxy* proxy = m_widget->getDrawWidgetProxy(); if (keyboardModifiers.testFlag(Qt::ControlModifier)) { // Zoom in/Zoom out @@ -200,7 +201,7 @@ void PDFDrawWidget::wheelEvent(QWheelEvent* event) const PDFReal zoom = m_widget->getDrawWidgetProxy()->getZoom(); const PDFReal zoomStep = std::pow(PDFDrawWidgetProxy::ZOOM_STEP, static_cast(angleDeltaY) / static_cast(QWheelEvent::DefaultDeltasPerStep)); const PDFReal newZoom = zoom * zoomStep; - m_widget->getDrawWidgetProxy()->zoom(newZoom); + proxy->zoom(newZoom); } else { @@ -211,8 +212,27 @@ void PDFDrawWidget::wheelEvent(QWheelEvent* event) { const QPoint angleDelta = event->angleDelta(); const bool shiftModifier = keyboardModifiers.testFlag(Qt::ShiftModifier); - const int stepVertical = shiftModifier ? m_widget->getVerticalScrollbar()->pageStep() : m_widget->getVerticalScrollbar()->singleStep(); - const int stepHorizontal = shiftModifier ? m_widget->getHorizontalScrollbar()->pageStep() : m_widget->getHorizontalScrollbar()->singleStep(); + int stepVertical = 0; + int stepHorizontal = shiftModifier ? m_widget->getHorizontalScrollbar()->pageStep() : m_widget->getHorizontalScrollbar()->singleStep(); + + if (proxy->isBlockMode()) + { + // In block mode, we must calculate pixel offsets differently - scrollbars corresponds to indices of blocks, + // not to the pixels. + QRect boundingBox = proxy->getPagesIntersectingRectBoundingBox(this->rect()); + + if (boundingBox.isEmpty()) + { + // This occurs, when we have not opened a document + boundingBox = this->rect(); + } + + stepVertical = shiftModifier ? boundingBox.height() : boundingBox.height() / 10; + } + else + { + stepVertical = shiftModifier ? m_widget->getVerticalScrollbar()->pageStep() : m_widget->getVerticalScrollbar()->singleStep(); + } const int scrollVertical = stepVertical * static_cast(angleDelta.y()) / static_cast(QWheelEvent::DefaultDeltasPerStep); const int scrollHorizontal = stepHorizontal * static_cast(angleDelta.x()) / static_cast(QWheelEvent::DefaultDeltasPerStep); @@ -220,7 +240,16 @@ void PDFDrawWidget::wheelEvent(QWheelEvent* event) scrollByPixels = QPoint(scrollHorizontal, scrollVertical); } - m_widget->getDrawWidgetProxy()->scrollByPixels(scrollByPixels); + QPoint offset = proxy->scrollByPixels(scrollByPixels); + + if (offset.y() == 0 && scrollByPixels.y() != 0 && proxy->isBlockMode()) + { + // We must move to another block (we are in block mode) + bool up = scrollByPixels.y() > 0; + + m_widget->getVerticalScrollbar()->setValue(m_widget->getVerticalScrollbar()->value() + (up ? -1 : 1)); + proxy->scrollByPixels(QPoint(0, up ? std::numeric_limits::min() : std::numeric_limits::max())); + } } event->accept(); diff --git a/PdfForQtLib/sources/pdfpagecontentprocessor.cpp b/PdfForQtLib/sources/pdfpagecontentprocessor.cpp index 959c711..68bb763 100644 --- a/PdfForQtLib/sources/pdfpagecontentprocessor.cpp +++ b/PdfForQtLib/sources/pdfpagecontentprocessor.cpp @@ -262,11 +262,12 @@ void PDFPageContentProcessor::reportRenderError(RenderErrorType type, QString me m_errorList.append(PDFRenderError(type, qMove(message))); } -void PDFPageContentProcessor::performPathPainting(const QPainterPath& path, bool stroke, bool fill, Qt::FillRule fillRule) +void PDFPageContentProcessor::performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule) { Q_UNUSED(path); Q_UNUSED(stroke); Q_UNUSED(fill); + Q_UNUSED(text); Q_UNUSED(fillRule); } @@ -1246,7 +1247,7 @@ void PDFPageContentProcessor::operatorPathStroke() if (!m_currentPath.isEmpty()) { m_currentPath.setFillRule(Qt::WindingFill); - performPathPainting(m_currentPath, true, false, Qt::WindingFill); + performPathPainting(m_currentPath, true, false, false, Qt::WindingFill); m_currentPath = QPainterPath(); } } @@ -1258,7 +1259,7 @@ void PDFPageContentProcessor::operatorPathCloseStroke() { m_currentPath.closeSubpath(); m_currentPath.setFillRule(Qt::WindingFill); - performPathPainting(m_currentPath, true, false, Qt::WindingFill); + performPathPainting(m_currentPath, true, false, false, Qt::WindingFill); m_currentPath = QPainterPath(); } } @@ -1268,7 +1269,7 @@ void PDFPageContentProcessor::operatorPathFillWinding() if (!m_currentPath.isEmpty()) { m_currentPath.setFillRule(Qt::WindingFill); - performPathPainting(m_currentPath, false, true, Qt::WindingFill); + performPathPainting(m_currentPath, false, true, false, Qt::WindingFill); m_currentPath = QPainterPath(); } } @@ -1278,7 +1279,7 @@ void PDFPageContentProcessor::operatorPathFillEvenOdd() if (!m_currentPath.isEmpty()) { m_currentPath.setFillRule(Qt::OddEvenFill); - performPathPainting(m_currentPath, false, true, Qt::OddEvenFill); + performPathPainting(m_currentPath, false, true, false, Qt::OddEvenFill); m_currentPath = QPainterPath(); } } @@ -1288,7 +1289,7 @@ void PDFPageContentProcessor::operatorPathFillStrokeWinding() if (!m_currentPath.isEmpty()) { m_currentPath.setFillRule(Qt::WindingFill); - performPathPainting(m_currentPath, true, true, Qt::WindingFill); + performPathPainting(m_currentPath, true, true, false, Qt::WindingFill); m_currentPath = QPainterPath(); } } @@ -1298,7 +1299,7 @@ void PDFPageContentProcessor::operatorPathFillStrokeEvenOdd() if (!m_currentPath.isEmpty()) { m_currentPath.setFillRule(Qt::OddEvenFill); - performPathPainting(m_currentPath, true, true, Qt::OddEvenFill); + performPathPainting(m_currentPath, true, true, false, Qt::OddEvenFill); m_currentPath = QPainterPath(); } } @@ -1309,7 +1310,7 @@ void PDFPageContentProcessor::operatorPathCloseFillStrokeWinding() { m_currentPath.closeSubpath(); m_currentPath.setFillRule(Qt::WindingFill); - performPathPainting(m_currentPath, true, true, Qt::WindingFill); + performPathPainting(m_currentPath, true, true, false, Qt::WindingFill); m_currentPath = QPainterPath(); } } @@ -1320,7 +1321,7 @@ void PDFPageContentProcessor::operatorPathCloseFillStrokeEvenOdd() { m_currentPath.closeSubpath(); m_currentPath.setFillRule(Qt::OddEvenFill); - performPathPainting(m_currentPath, true, true, Qt::OddEvenFill); + performPathPainting(m_currentPath, true, true, false, Qt::OddEvenFill); m_currentPath = QPainterPath(); } } @@ -1809,7 +1810,7 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence) { QMatrix textRenderingMatrix = adjustMatrix * textMatrix; QPainterPath transformedGlyph = textRenderingMatrix.map(glyphPath); - performPathPainting(transformedGlyph, stroke, fill, transformedGlyph.fillRule()); + performPathPainting(transformedGlyph, stroke, fill, true, transformedGlyph.fillRule()); if (clipped) { diff --git a/PdfForQtLib/sources/pdfpagecontentprocessor.h b/PdfForQtLib/sources/pdfpagecontentprocessor.h index 0e8516f..ea2f0b6 100644 --- a/PdfForQtLib/sources/pdfpagecontentprocessor.h +++ b/PdfForQtLib/sources/pdfpagecontentprocessor.h @@ -347,8 +347,9 @@ protected: /// \param path Path, which should be drawn (can be emtpy - in that case nothing happens) /// \param stroke Stroke the path /// \param fill Fill the path using given rule + /// \param text Is text being drawn? /// \param fillRule Fill rule used in the fill mode - virtual void performPathPainting(const QPainterPath& path, bool stroke, bool fill, Qt::FillRule fillRule); + virtual void performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule); /// This function has to be implemented in the client drawing implementation, it should /// clip along the path (intersect with current clipping path). diff --git a/PdfForQtLib/sources/pdfpainter.cpp b/PdfForQtLib/sources/pdfpainter.cpp index bac916f..d73e88b 100644 --- a/PdfForQtLib/sources/pdfpainter.cpp +++ b/PdfForQtLib/sources/pdfpainter.cpp @@ -40,7 +40,7 @@ PDFPainter::~PDFPainter() m_painter->restore(); } -void PDFPainter::performPathPainting(const QPainterPath& path, bool stroke, bool fill, Qt::FillRule fillRule) +void PDFPainter::performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule) { if ((!stroke && !fill) || path.isEmpty()) { @@ -48,6 +48,10 @@ void PDFPainter::performPathPainting(const QPainterPath& path, bool stroke, bool return; } + // Set antialiasing + const bool antialiasing = (text && m_features.testFlag(PDFRenderer::TextAntialiasing)) || (!text && m_features.testFlag(PDFRenderer::Antialiasing)); + m_painter->setRenderHint(QPainter::Antialiasing, antialiasing); + if (stroke) { m_painter->setPen(getCurrentPen()); diff --git a/PdfForQtLib/sources/pdfpainter.h b/PdfForQtLib/sources/pdfpainter.h index 1052dbf..d8008f9 100644 --- a/PdfForQtLib/sources/pdfpainter.h +++ b/PdfForQtLib/sources/pdfpainter.h @@ -49,7 +49,7 @@ public: virtual ~PDFPainter() override; protected: - virtual void performPathPainting(const QPainterPath& path, bool stroke, bool fill, Qt::FillRule fillRule) override; + virtual void performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule) override; virtual void performClipping(const QPainterPath& path, Qt::FillRule fillRule) override; virtual void performUpdateGraphicsState(const PDFPageContentProcessorState& state) override; virtual void performSaveGraphicState(ProcessOrder order) override; diff --git a/PdfForQtLib/sources/pdfrenderer.cpp b/PdfForQtLib/sources/pdfrenderer.cpp index 19006ec..b788107 100644 --- a/PdfForQtLib/sources/pdfrenderer.cpp +++ b/PdfForQtLib/sources/pdfrenderer.cpp @@ -30,9 +30,8 @@ PDFRenderer::PDFRenderer(const PDFDocument* document, const PDFFontCache* fontCa Q_ASSERT(document); } -// TODO: Dodelat features, napr. antialiasing // TODO: Dodelat rotovani stranek -// TODO: Dodelat obrazky +// TODO: Dodelat obrazky - SMOOTH QList PDFRenderer::render(QPainter* painter, const QRectF& rectangle, size_t pageIndex) const {