Minor bugfixes

This commit is contained in:
Jakub Melka 2019-05-04 18:22:40 +02:00
parent 3ad7485dbf
commit 0447b9e3a1
8 changed files with 90 additions and 27 deletions

View File

@ -408,7 +408,7 @@ void PDFDrawWidgetProxy::update()
} }
else else
{ {
m_currentBlock = qBound<PDFInteger>(0, m_currentBlock, m_controller->getBlockCount()); m_currentBlock = qBound<PDFInteger>(0, m_currentBlock, m_controller->getBlockCount() - 1);
} }
} }
else else
@ -579,6 +579,26 @@ std::vector<PDFInteger> PDFDrawWidgetProxy::getPagesIntersectingRect(QRect rect)
return pages; 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) void PDFDrawWidgetProxy::performOperation(Operation operation)
{ {
switch (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()); setHorizontalOffset(m_horizontalOffset + offset.x());
setVerticalOffset(m_verticalOffset + offset.y()); setVerticalOffset(m_verticalOffset + offset.y());
return QPoint(m_horizontalOffset - oldHorizontalOffset, m_verticalOffset - oldVerticalOffset);
} }
void PDFDrawWidgetProxy::zoom(PDFReal zoom) void PDFDrawWidgetProxy::zoom(PDFReal zoom)

View File

@ -170,9 +170,9 @@ public:
void performOperation(Operation operation); void performOperation(Operation operation);
/// Scrolls by pixels, if it is possible. If it is not possible to scroll, /// 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 /// \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 /// Sets the zoom. Tries to preserve current offsets (so the current visible
/// area will be visible after the zoom). /// area will be visible after the zoom).
@ -194,6 +194,14 @@ public:
/// \param rect Rectangle to test /// \param rect Rectangle to test
std::vector<PDFInteger> getPagesIntersectingRect(QRect rect) const; std::vector<PDFInteger> 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; static constexpr PDFReal ZOOM_STEP = 1.2;
signals: signals:
@ -237,10 +245,6 @@ private:
/// Converts rectangle from device space to the pixel space /// Converts rectangle from device space to the pixel space
QRectF fromDeviceSpace(const QRectF& rect) const; 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 onHorizontalScrollbarValueChanged(int value);
void onVerticalScrollbarValueChanged(int value); void onVerticalScrollbarValueChanged(int value);

View File

@ -193,6 +193,7 @@ void PDFDrawWidget::wheelEvent(QWheelEvent* event)
{ {
Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers(); Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers();
PDFDrawWidgetProxy* proxy = m_widget->getDrawWidgetProxy();
if (keyboardModifiers.testFlag(Qt::ControlModifier)) if (keyboardModifiers.testFlag(Qt::ControlModifier))
{ {
// Zoom in/Zoom out // Zoom in/Zoom out
@ -200,7 +201,7 @@ void PDFDrawWidget::wheelEvent(QWheelEvent* event)
const PDFReal zoom = m_widget->getDrawWidgetProxy()->getZoom(); const PDFReal zoom = m_widget->getDrawWidgetProxy()->getZoom();
const PDFReal zoomStep = std::pow(PDFDrawWidgetProxy::ZOOM_STEP, static_cast<PDFReal>(angleDeltaY) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep)); const PDFReal zoomStep = std::pow(PDFDrawWidgetProxy::ZOOM_STEP, static_cast<PDFReal>(angleDeltaY) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep));
const PDFReal newZoom = zoom * zoomStep; const PDFReal newZoom = zoom * zoomStep;
m_widget->getDrawWidgetProxy()->zoom(newZoom); proxy->zoom(newZoom);
} }
else else
{ {
@ -211,8 +212,27 @@ void PDFDrawWidget::wheelEvent(QWheelEvent* event)
{ {
const QPoint angleDelta = event->angleDelta(); const QPoint angleDelta = event->angleDelta();
const bool shiftModifier = keyboardModifiers.testFlag(Qt::ShiftModifier); const bool shiftModifier = keyboardModifiers.testFlag(Qt::ShiftModifier);
const int stepVertical = shiftModifier ? m_widget->getVerticalScrollbar()->pageStep() : m_widget->getVerticalScrollbar()->singleStep(); int stepVertical = 0;
const int stepHorizontal = shiftModifier ? m_widget->getHorizontalScrollbar()->pageStep() : m_widget->getHorizontalScrollbar()->singleStep(); 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<PDFReal>(angleDelta.y()) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep); const int scrollVertical = stepVertical * static_cast<PDFReal>(angleDelta.y()) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep);
const int scrollHorizontal = stepHorizontal * static_cast<PDFReal>(angleDelta.x()) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep); const int scrollHorizontal = stepHorizontal * static_cast<PDFReal>(angleDelta.x()) / static_cast<PDFReal>(QWheelEvent::DefaultDeltasPerStep);
@ -220,7 +240,16 @@ void PDFDrawWidget::wheelEvent(QWheelEvent* event)
scrollByPixels = QPoint(scrollHorizontal, scrollVertical); 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<int>::min() : std::numeric_limits<int>::max()));
}
} }
event->accept(); event->accept();

View File

@ -262,11 +262,12 @@ void PDFPageContentProcessor::reportRenderError(RenderErrorType type, QString me
m_errorList.append(PDFRenderError(type, qMove(message))); 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(path);
Q_UNUSED(stroke); Q_UNUSED(stroke);
Q_UNUSED(fill); Q_UNUSED(fill);
Q_UNUSED(text);
Q_UNUSED(fillRule); Q_UNUSED(fillRule);
} }
@ -1246,7 +1247,7 @@ void PDFPageContentProcessor::operatorPathStroke()
if (!m_currentPath.isEmpty()) if (!m_currentPath.isEmpty())
{ {
m_currentPath.setFillRule(Qt::WindingFill); m_currentPath.setFillRule(Qt::WindingFill);
performPathPainting(m_currentPath, true, false, Qt::WindingFill); performPathPainting(m_currentPath, true, false, false, Qt::WindingFill);
m_currentPath = QPainterPath(); m_currentPath = QPainterPath();
} }
} }
@ -1258,7 +1259,7 @@ void PDFPageContentProcessor::operatorPathCloseStroke()
{ {
m_currentPath.closeSubpath(); m_currentPath.closeSubpath();
m_currentPath.setFillRule(Qt::WindingFill); m_currentPath.setFillRule(Qt::WindingFill);
performPathPainting(m_currentPath, true, false, Qt::WindingFill); performPathPainting(m_currentPath, true, false, false, Qt::WindingFill);
m_currentPath = QPainterPath(); m_currentPath = QPainterPath();
} }
} }
@ -1268,7 +1269,7 @@ void PDFPageContentProcessor::operatorPathFillWinding()
if (!m_currentPath.isEmpty()) if (!m_currentPath.isEmpty())
{ {
m_currentPath.setFillRule(Qt::WindingFill); m_currentPath.setFillRule(Qt::WindingFill);
performPathPainting(m_currentPath, false, true, Qt::WindingFill); performPathPainting(m_currentPath, false, true, false, Qt::WindingFill);
m_currentPath = QPainterPath(); m_currentPath = QPainterPath();
} }
} }
@ -1278,7 +1279,7 @@ void PDFPageContentProcessor::operatorPathFillEvenOdd()
if (!m_currentPath.isEmpty()) if (!m_currentPath.isEmpty())
{ {
m_currentPath.setFillRule(Qt::OddEvenFill); m_currentPath.setFillRule(Qt::OddEvenFill);
performPathPainting(m_currentPath, false, true, Qt::OddEvenFill); performPathPainting(m_currentPath, false, true, false, Qt::OddEvenFill);
m_currentPath = QPainterPath(); m_currentPath = QPainterPath();
} }
} }
@ -1288,7 +1289,7 @@ void PDFPageContentProcessor::operatorPathFillStrokeWinding()
if (!m_currentPath.isEmpty()) if (!m_currentPath.isEmpty())
{ {
m_currentPath.setFillRule(Qt::WindingFill); m_currentPath.setFillRule(Qt::WindingFill);
performPathPainting(m_currentPath, true, true, Qt::WindingFill); performPathPainting(m_currentPath, true, true, false, Qt::WindingFill);
m_currentPath = QPainterPath(); m_currentPath = QPainterPath();
} }
} }
@ -1298,7 +1299,7 @@ void PDFPageContentProcessor::operatorPathFillStrokeEvenOdd()
if (!m_currentPath.isEmpty()) if (!m_currentPath.isEmpty())
{ {
m_currentPath.setFillRule(Qt::OddEvenFill); m_currentPath.setFillRule(Qt::OddEvenFill);
performPathPainting(m_currentPath, true, true, Qt::OddEvenFill); performPathPainting(m_currentPath, true, true, false, Qt::OddEvenFill);
m_currentPath = QPainterPath(); m_currentPath = QPainterPath();
} }
} }
@ -1309,7 +1310,7 @@ void PDFPageContentProcessor::operatorPathCloseFillStrokeWinding()
{ {
m_currentPath.closeSubpath(); m_currentPath.closeSubpath();
m_currentPath.setFillRule(Qt::WindingFill); m_currentPath.setFillRule(Qt::WindingFill);
performPathPainting(m_currentPath, true, true, Qt::WindingFill); performPathPainting(m_currentPath, true, true, false, Qt::WindingFill);
m_currentPath = QPainterPath(); m_currentPath = QPainterPath();
} }
} }
@ -1320,7 +1321,7 @@ void PDFPageContentProcessor::operatorPathCloseFillStrokeEvenOdd()
{ {
m_currentPath.closeSubpath(); m_currentPath.closeSubpath();
m_currentPath.setFillRule(Qt::OddEvenFill); m_currentPath.setFillRule(Qt::OddEvenFill);
performPathPainting(m_currentPath, true, true, Qt::OddEvenFill); performPathPainting(m_currentPath, true, true, false, Qt::OddEvenFill);
m_currentPath = QPainterPath(); m_currentPath = QPainterPath();
} }
} }
@ -1809,7 +1810,7 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence)
{ {
QMatrix textRenderingMatrix = adjustMatrix * textMatrix; QMatrix textRenderingMatrix = adjustMatrix * textMatrix;
QPainterPath transformedGlyph = textRenderingMatrix.map(glyphPath); QPainterPath transformedGlyph = textRenderingMatrix.map(glyphPath);
performPathPainting(transformedGlyph, stroke, fill, transformedGlyph.fillRule()); performPathPainting(transformedGlyph, stroke, fill, true, transformedGlyph.fillRule());
if (clipped) if (clipped)
{ {

View File

@ -347,8 +347,9 @@ protected:
/// \param path Path, which should be drawn (can be emtpy - in that case nothing happens) /// \param path Path, which should be drawn (can be emtpy - in that case nothing happens)
/// \param stroke Stroke the path /// \param stroke Stroke the path
/// \param fill Fill the path using given rule /// \param fill Fill the path using given rule
/// \param text Is text being drawn?
/// \param fillRule Fill rule used in the fill mode /// \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 /// This function has to be implemented in the client drawing implementation, it should
/// clip along the path (intersect with current clipping path). /// clip along the path (intersect with current clipping path).

View File

@ -40,7 +40,7 @@ PDFPainter::~PDFPainter()
m_painter->restore(); 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()) if ((!stroke && !fill) || path.isEmpty())
{ {
@ -48,6 +48,10 @@ void PDFPainter::performPathPainting(const QPainterPath& path, bool stroke, bool
return; 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) if (stroke)
{ {
m_painter->setPen(getCurrentPen()); m_painter->setPen(getCurrentPen());

View File

@ -49,7 +49,7 @@ public:
virtual ~PDFPainter() override; virtual ~PDFPainter() override;
protected: 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 performClipping(const QPainterPath& path, Qt::FillRule fillRule) override;
virtual void performUpdateGraphicsState(const PDFPageContentProcessorState& state) override; virtual void performUpdateGraphicsState(const PDFPageContentProcessorState& state) override;
virtual void performSaveGraphicState(ProcessOrder order) override; virtual void performSaveGraphicState(ProcessOrder order) override;

View File

@ -30,9 +30,8 @@ PDFRenderer::PDFRenderer(const PDFDocument* document, const PDFFontCache* fontCa
Q_ASSERT(document); Q_ASSERT(document);
} }
// TODO: Dodelat features, napr. antialiasing
// TODO: Dodelat rotovani stranek // TODO: Dodelat rotovani stranek
// TODO: Dodelat obrazky // TODO: Dodelat obrazky - SMOOTH
QList<PDFRenderError> PDFRenderer::render(QPainter* painter, const QRectF& rectangle, size_t pageIndex) const QList<PDFRenderError> PDFRenderer::render(QPainter* painter, const QRectF& rectangle, size_t pageIndex) const
{ {