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
{
m_currentBlock = qBound<PDFInteger>(0, m_currentBlock, m_controller->getBlockCount());
m_currentBlock = qBound<PDFInteger>(0, m_currentBlock, m_controller->getBlockCount() - 1);
}
}
else
@ -579,6 +579,26 @@ std::vector<PDFInteger> 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)

View File

@ -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<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;
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);

View File

@ -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<PDFReal>(angleDeltaY) / static_cast<PDFReal>(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<PDFReal>(angleDelta.y()) / 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);
}
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();

View File

@ -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)
{

View File

@ -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).

View File

@ -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());

View File

@ -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;

View File

@ -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<PDFRenderError> PDFRenderer::render(QPainter* painter, const QRectF& rectangle, size_t pageIndex) const
{