mirror of https://github.com/JakubMelka/PDF4QT.git
Issue #123: Oprava klipování
This commit is contained in:
parent
7ad04b55ee
commit
5eb5069173
|
@ -22,6 +22,7 @@
|
||||||
#include <QRawFont>
|
#include <QRawFont>
|
||||||
#include <QPainterPath>
|
#include <QPainterPath>
|
||||||
#include <QPaintEngine>
|
#include <QPaintEngine>
|
||||||
|
#include <QPainterPathStroker>
|
||||||
|
|
||||||
#include <Blend2d.h>
|
#include <Blend2d.h>
|
||||||
|
|
||||||
|
@ -103,6 +104,7 @@ private:
|
||||||
NeedsResolve
|
NeedsResolve
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ClipMode resolveClipping(const QRectF& rect) const;
|
||||||
ClipMode resolveClipping(const QPainterPath& path) const;
|
ClipMode resolveClipping(const QPainterPath& path) const;
|
||||||
|
|
||||||
QImage& m_qtOffscreenBuffer;
|
QImage& m_qtOffscreenBuffer;
|
||||||
|
@ -118,9 +120,8 @@ private:
|
||||||
|
|
||||||
bool m_currentIsClipEnabled = false;
|
bool m_currentIsClipEnabled = false;
|
||||||
bool m_clipSingleRect = false;
|
bool m_clipSingleRect = false;
|
||||||
std::optional<QRegion> m_clipRegion;
|
QPainterPath m_finalClipPath;
|
||||||
std::optional<QPainterPath> m_clipPath;
|
QRectF m_finalClipPathBoundingBox;
|
||||||
std::optional<QPainterPath> m_finalClipPath;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PDFBLPaintDevice::PDFBLPaintDevice(QImage& offscreenBuffer, bool isMultithreaded) :
|
PDFBLPaintDevice::PDFBLPaintDevice(QImage& offscreenBuffer, bool isMultithreaded) :
|
||||||
|
@ -335,14 +336,39 @@ void PDFBLPaintEngine::updateState(const QPaintEngineState& updatedState)
|
||||||
|
|
||||||
void PDFBLPaintEngine::drawRects(const QRect* rects, int rectCount)
|
void PDFBLPaintEngine::drawRects(const QRect* rects, int rectCount)
|
||||||
{
|
{
|
||||||
|
QRect boundingRect;
|
||||||
|
|
||||||
BLArray<BLRectI> blRects;
|
BLArray<BLRectI> blRects;
|
||||||
blRects.reserve(rectCount);
|
blRects.reserve(rectCount);
|
||||||
|
|
||||||
for (int i = 0; i < rectCount; ++i)
|
for (int i = 0; i < rectCount; ++i)
|
||||||
{
|
{
|
||||||
|
boundingRect = boundingRect.united(rects[i]);
|
||||||
blRects.append(getBLRect(rects[i]));
|
blRects.append(getBLRect(rects[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRect mappedBoundingRect = m_currentTransform.mapRect(boundingRect);
|
||||||
|
ClipMode clipMode = resolveClipping(mappedBoundingRect);
|
||||||
|
switch (clipMode)
|
||||||
|
{
|
||||||
|
case ClipMode::NoClip:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ClipMode::NotVisible:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case ClipMode::NeedsResolve:
|
||||||
|
{
|
||||||
|
for (int i = 0; i < rectCount; ++i)
|
||||||
|
{
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRect(rects[i]);
|
||||||
|
drawPathImpl(path, true, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isFillActive())
|
if (isFillActive())
|
||||||
{
|
{
|
||||||
m_blContext->fillRectArray(blRects.view());
|
m_blContext->fillRectArray(blRects.view());
|
||||||
|
@ -356,14 +382,39 @@ void PDFBLPaintEngine::drawRects(const QRect* rects, int rectCount)
|
||||||
|
|
||||||
void PDFBLPaintEngine::drawRects(const QRectF* rects, int rectCount)
|
void PDFBLPaintEngine::drawRects(const QRectF* rects, int rectCount)
|
||||||
{
|
{
|
||||||
|
QRectF boundingRect;
|
||||||
|
|
||||||
BLArray<BLRect> blRects;
|
BLArray<BLRect> blRects;
|
||||||
blRects.reserve(rectCount);
|
blRects.reserve(rectCount);
|
||||||
|
|
||||||
for (int i = 0; i < rectCount; ++i)
|
for (int i = 0; i < rectCount; ++i)
|
||||||
{
|
{
|
||||||
|
boundingRect = boundingRect.united(rects[i]);
|
||||||
blRects.append(getBLRect(rects[i]));
|
blRects.append(getBLRect(rects[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRectF mappedBoundingRect = m_currentTransform.mapRect(boundingRect);
|
||||||
|
ClipMode clipMode = resolveClipping(mappedBoundingRect);
|
||||||
|
switch (clipMode)
|
||||||
|
{
|
||||||
|
case ClipMode::NoClip:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ClipMode::NotVisible:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case ClipMode::NeedsResolve:
|
||||||
|
{
|
||||||
|
for (int i = 0; i < rectCount; ++i)
|
||||||
|
{
|
||||||
|
QPainterPath path;
|
||||||
|
path.addRect(rects[i]);
|
||||||
|
drawPathImpl(path, true, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isFillActive())
|
if (isFillActive())
|
||||||
{
|
{
|
||||||
m_blContext->fillRectArray(blRects.view());
|
m_blContext->fillRectArray(blRects.view());
|
||||||
|
@ -427,24 +478,62 @@ void PDFBLPaintEngine::drawPathImpl(const QPainterPath& path, bool enableStroke,
|
||||||
QPainterPath transformedPath = m_currentTransform.map(path);
|
QPainterPath transformedPath = m_currentTransform.map(path);
|
||||||
ClipMode clipMode = resolveClipping(transformedPath);
|
ClipMode clipMode = resolveClipping(transformedPath);
|
||||||
|
|
||||||
|
setFillRule(path.fillRule());
|
||||||
|
|
||||||
switch (clipMode)
|
switch (clipMode)
|
||||||
{
|
{
|
||||||
case ClipMode::NoClip:
|
case ClipMode::NoClip:
|
||||||
// Do as normal
|
// Do as normal
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case pdf::PDFBLPaintEngine::ClipMode::NotVisible:
|
case ClipMode::NotVisible:
|
||||||
// Graphics is not visible
|
// Graphics is not visible
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case pdf::PDFBLPaintEngine::ClipMode::NeedsResolve:
|
case ClipMode::NeedsResolve:
|
||||||
break;
|
{
|
||||||
|
if (m_finalClipPath.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFillActive() && enableFill)
|
||||||
|
{
|
||||||
|
QPainterPath fillPath = transformedPath.intersected(m_finalClipPath);
|
||||||
|
|
||||||
|
if (!fillPath.isEmpty())
|
||||||
|
{
|
||||||
|
m_blContext->save();
|
||||||
|
m_blContext->resetMatrix();
|
||||||
|
m_blContext->fillPath(getBLPath(fillPath));
|
||||||
|
m_blContext->restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStrokeActive() && enableStroke)
|
||||||
|
{
|
||||||
|
QPainterPathStroker stroker(m_currentPen);
|
||||||
|
QPainterPath strokedPath = stroker.createStroke(path);
|
||||||
|
QPainterPath transformedStrokedPath = m_currentTransform.map(strokedPath);
|
||||||
|
QPainterPath finalTransformedStrokedPath = transformedStrokedPath.intersected(m_finalClipPath);
|
||||||
|
|
||||||
|
BLVarCore strokeStyle;
|
||||||
|
if (!finalTransformedStrokedPath.isEmpty() && m_blContext->getStrokeStyle(strokeStyle) == BL_SUCCESS)
|
||||||
|
{
|
||||||
|
m_blContext->save();
|
||||||
|
m_blContext->resetMatrix();
|
||||||
|
m_blContext->setFillStyle(strokeStyle);
|
||||||
|
m_blContext->fillPath(getBLPath(finalTransformedStrokedPath));
|
||||||
|
m_blContext->restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BLPath blPath = getBLPath(path);
|
BLPath blPath = getBLPath(path);
|
||||||
|
|
||||||
setFillRule(path.fillRule());
|
|
||||||
|
|
||||||
if (isFillActive() && enableFill)
|
if (isFillActive() && enableFill)
|
||||||
{
|
{
|
||||||
m_blContext->fillPath(blPath);
|
m_blContext->fillPath(blPath);
|
||||||
|
@ -578,6 +667,14 @@ void PDFBLPaintEngine::drawImage(const QRectF& r, const QImage& pm, const QRectF
|
||||||
{
|
{
|
||||||
Q_UNUSED(flags);
|
Q_UNUSED(flags);
|
||||||
|
|
||||||
|
QRectF transformedRect = m_currentTransform.mapRect(r);
|
||||||
|
ClipMode clipMode = resolveClipping(transformedRect);
|
||||||
|
|
||||||
|
if (clipMode == ClipMode::NotVisible)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QImage image = pm;
|
QImage image = pm;
|
||||||
|
|
||||||
if (image.format() != QImage::Format_ARGB32_Premultiplied)
|
if (image.format() != QImage::Format_ARGB32_Premultiplied)
|
||||||
|
@ -936,104 +1033,99 @@ void PDFBLPaintEngine::updateClipping(std::optional<QRegion> clipRegion,
|
||||||
std::optional<QPainterPath> clipPath,
|
std::optional<QPainterPath> clipPath,
|
||||||
Qt::ClipOperation clipOperation)
|
Qt::ClipOperation clipOperation)
|
||||||
{
|
{
|
||||||
|
QPainterPath finalClipPath;
|
||||||
|
|
||||||
|
if (clipRegion.has_value())
|
||||||
|
{
|
||||||
|
finalClipPath.addRegion(clipRegion.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clipPath.has_value())
|
||||||
|
{
|
||||||
|
finalClipPath.addPath(clipPath.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
finalClipPath = m_currentTransform.map(finalClipPath);
|
||||||
|
|
||||||
switch (clipOperation)
|
switch (clipOperation)
|
||||||
{
|
{
|
||||||
case Qt::NoClip:
|
case Qt::NoClip:
|
||||||
m_clipRegion.reset();
|
m_finalClipPath = QPainterPath();
|
||||||
m_clipPath.reset();
|
m_finalClipPathBoundingBox = QRectF();
|
||||||
m_finalClipPath.reset();
|
|
||||||
m_clipSingleRect = false;
|
m_clipSingleRect = false;
|
||||||
m_blContext->restoreClipping();
|
m_blContext->restoreClipping();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case Qt::ReplaceClip:
|
case Qt::ReplaceClip:
|
||||||
{
|
{
|
||||||
m_clipPath = std::move(clipPath);
|
m_finalClipPath = std::move(finalClipPath);
|
||||||
m_clipRegion = std::move(clipRegion);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Qt::IntersectClip:
|
case Qt::IntersectClip:
|
||||||
{
|
{
|
||||||
if (m_clipPath.has_value())
|
m_finalClipPath = m_finalClipPath.intersected(finalClipPath);
|
||||||
{
|
|
||||||
if (clipPath.has_value())
|
|
||||||
{
|
|
||||||
*m_clipPath = m_clipPath->intersected(*clipPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_clipPath = std::move(clipPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_clipRegion.has_value())
|
|
||||||
{
|
|
||||||
if (clipRegion.has_value())
|
|
||||||
{
|
|
||||||
*m_clipRegion = m_clipRegion->intersected(*clipRegion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_clipRegion = std::move(clipRegion);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_clipSingleRect = m_clipRegion.has_value() && !m_clipPath.has_value() && m_clipRegion->rectCount() == 1;
|
m_clipSingleRect = false;
|
||||||
|
m_finalClipPathBoundingBox = m_finalClipPath.controlPointRect();
|
||||||
|
|
||||||
|
if (m_finalClipPath.elementCount() == 5)
|
||||||
|
{
|
||||||
|
QRectF testRect = m_finalClipPathBoundingBox.adjusted(1.0, 1.0, -2.0, -2.0);
|
||||||
|
m_clipSingleRect = m_finalClipPath.contains(testRect);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_clipSingleRect)
|
if (m_clipSingleRect)
|
||||||
{
|
{
|
||||||
QRegion transformedRegion = m_currentTransform.map(m_clipRegion.value());
|
BLMatrix2D matrix = m_blContext->userMatrix();
|
||||||
m_blContext->clipToRect(getBLRect(transformedRegion.boundingRect()));
|
m_blContext->resetMatrix();
|
||||||
|
m_blContext->clipToRect(getBLRect(m_finalClipPath.boundingRect()));
|
||||||
|
m_blContext->setMatrix(matrix);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_blContext->restoreClipping();
|
m_blContext->restoreClipping();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_finalClipPath = QPainterPath();
|
|
||||||
|
|
||||||
QPainterPath clip1;
|
|
||||||
QPainterPath clip2;
|
|
||||||
|
|
||||||
if (m_clipPath.has_value())
|
|
||||||
{
|
|
||||||
clip1 = m_clipPath.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_clipRegion.has_value())
|
|
||||||
{
|
|
||||||
clip2.addRegion(m_clipRegion.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!clip1.isEmpty() && !clip2.isEmpty())
|
|
||||||
{
|
|
||||||
m_finalClipPath = clip1.intersected(clip2);
|
|
||||||
}
|
|
||||||
else if (!clip1.isEmpty())
|
|
||||||
{
|
|
||||||
m_finalClipPath = std::move(clip1);
|
|
||||||
}
|
|
||||||
else if (!clip2.isEmpty())
|
|
||||||
{
|
|
||||||
m_finalClipPath = std::move(clip2);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_finalClipPath = m_currentTransform.map(m_finalClipPath.value());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PDFBLPaintEngine::ClipMode PDFBLPaintEngine::resolveClipping(const QPainterPath& path) const
|
PDFBLPaintEngine::ClipMode PDFBLPaintEngine::resolveClipping(const QRectF& rect) const
|
||||||
{
|
{
|
||||||
if (!m_currentIsClipEnabled || m_clipSingleRect || !m_finalClipPath.has_value() || m_finalClipPath->isEmpty())
|
if (!m_currentIsClipEnabled || m_clipSingleRect || m_finalClipPath.isEmpty())
|
||||||
{
|
{
|
||||||
return ClipMode::NoClip;
|
return ClipMode::NoClip;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF clipRect = m_finalClipPath->controlPointRect();
|
if (m_finalClipPath.isEmpty())
|
||||||
|
{
|
||||||
|
return ClipMode::NotVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF clipRect = m_finalClipPathBoundingBox;
|
||||||
|
|
||||||
|
if (!rect.intersects(clipRect))
|
||||||
|
{
|
||||||
|
return ClipMode::NotVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClipMode::NeedsResolve;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFBLPaintEngine::ClipMode PDFBLPaintEngine::resolveClipping(const QPainterPath& path) const
|
||||||
|
{
|
||||||
|
if (!m_currentIsClipEnabled || m_clipSingleRect)
|
||||||
|
{
|
||||||
|
return ClipMode::NoClip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_finalClipPath.isEmpty())
|
||||||
|
{
|
||||||
|
return ClipMode::NotVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF clipRect = m_finalClipPathBoundingBox;
|
||||||
QRectF pathRect = path.controlPointRect();
|
QRectF pathRect = path.controlPointRect();
|
||||||
|
|
||||||
if (!pathRect.intersects(clipRect))
|
if (!pathRect.intersects(clipRect))
|
||||||
|
|
Loading…
Reference in New Issue