summaryrefslogtreecommitdiffstats
path: root/src/openvg/qpaintengine_vg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvg/qpaintengine_vg.cpp')
-rw-r--r--src/openvg/qpaintengine_vg.cpp184
1 files changed, 180 insertions, 4 deletions
diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp
index c7fe604..7a962e4 100644
--- a/src/openvg/qpaintengine_vg.cpp
+++ b/src/openvg/qpaintengine_vg.cpp
@@ -142,6 +142,8 @@ public:
void ensureMask(QVGPaintEngine *engine, int width, int height);
void modifyMask
(QVGPaintEngine *engine, VGMaskOperation op, const QRegion& region);
+ void modifyMask
+ (QVGPaintEngine *engine, VGMaskOperation op, const QRect& rect);
#endif
VGint maxScissorRects; // Maximum scissor rectangles for clipping.
@@ -1611,13 +1613,106 @@ void QVGPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
{
- clip(QRegion(rect), op);
+ Q_D(QVGPaintEngine);
+
+ d->dirty |= QPaintEngine::DirtyClipRegion;
+
+ // If we have a non-simple transform, then use path-based clipping.
+ if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) {
+ QPaintEngineEx::clip(rect, op);
+ return;
+ }
+
+ switch (op) {
+ case Qt::NoClip:
+ {
+ d->maskValid = false;
+ d->maskIsSet = true;
+ d->maskRect = QRect();
+ vgSeti(VG_MASKING, VG_FALSE);
+ }
+ break;
+
+ case Qt::ReplaceClip:
+ {
+ QRect r = d->transform.mapRect(rect);
+ if (isDefaultClipRect(r)) {
+ // Replacing the clip with a full-window region is the
+ // same as turning off clipping.
+ if (d->maskValid)
+ vgSeti(VG_MASKING, VG_FALSE);
+ d->maskValid = false;
+ d->maskIsSet = true;
+ d->maskRect = QRect();
+ } else {
+ // Special case: if the intersection of the system
+ // clip and "r" is a single rectangle, then use the
+ // scissor for clipping. We try to avoid allocating a
+ // QRegion copy on the heap for the test if we can.
+ QRegion clip = d->systemClip; // Reference-counted, no alloc.
+ QRect clipRect;
+ if (clip.numRects() == 1) {
+ clipRect = clip.boundingRect().intersected(r);
+ } else if (clip.isEmpty()) {
+ clipRect = r;
+ } else {
+ clip = clip.intersect(r);
+ if (clip.numRects() != 1) {
+ d->maskValid = false;
+ d->maskIsSet = false;
+ d->maskRect = QRect();
+ d->modifyMask(this, VG_FILL_MASK, r);
+ break;
+ }
+ clipRect = clip.boundingRect();
+ }
+ d->maskValid = false;
+ d->maskIsSet = false;
+ d->maskRect = clipRect;
+ vgSeti(VG_MASKING, VG_FALSE);
+ updateScissor();
+ }
+ }
+ break;
+
+ case Qt::IntersectClip:
+ {
+ QRect r = d->transform.mapRect(rect);
+ if (d->maskIsSet && isDefaultClipRect(r)) {
+ // Intersecting a full-window clip with a full-window
+ // region is the same as turning off clipping.
+ if (d->maskValid)
+ vgSeti(VG_MASKING, VG_FALSE);
+ d->maskValid = false;
+ d->maskIsSet = true;
+ d->maskRect = QRect();
+ } else {
+ d->modifyMask(this, VG_INTERSECT_MASK, r);
+ }
+ }
+ break;
+
+ case Qt::UniteClip:
+ {
+ // If we already have a full-window clip, then uniting a
+ // region with it will do nothing. Otherwise union.
+ if (!(d->maskIsSet))
+ d->modifyMask(this, VG_UNION_MASK, d->transform.mapRect(rect));
+ }
+ break;
+ }
}
void QVGPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
{
Q_D(QVGPaintEngine);
+ // Use the QRect case if the region consists of a single rectangle.
+ if (region.numRects() == 1) {
+ clip(region.boundingRect(), op);
+ return;
+ }
+
d->dirty |= QPaintEngine::DirtyClipRegion;
// If we have a non-simple transform, then use path-based clipping.
@@ -1656,10 +1751,10 @@ void QVGPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
clip = r;
else
clip = clip.intersect(r);
- if (r.numRects() == 1) {
+ if (clip.numRects() == 1) {
d->maskValid = false;
d->maskIsSet = false;
- d->maskRect = r.boundingRect();
+ d->maskRect = clip.boundingRect();
vgSeti(VG_MASKING, VG_FALSE);
updateScissor();
} else {
@@ -1707,11 +1802,61 @@ void QVGPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
}
}
+#if !defined(QVG_NO_RENDER_TO_MASK)
+
+// Copied from qpathclipper.cpp.
+static bool qt_vg_pathToRect(const QPainterPath &path, QRectF *rect)
+{
+ if (path.elementCount() != 5)
+ return false;
+
+ const bool mightBeRect = path.elementAt(0).isMoveTo()
+ && path.elementAt(1).isLineTo()
+ && path.elementAt(2).isLineTo()
+ && path.elementAt(3).isLineTo()
+ && path.elementAt(4).isLineTo();
+
+ if (!mightBeRect)
+ return false;
+
+ const qreal x1 = path.elementAt(0).x;
+ const qreal y1 = path.elementAt(0).y;
+
+ const qreal x2 = path.elementAt(1).x;
+ const qreal y2 = path.elementAt(2).y;
+
+ if (path.elementAt(1).y != y1)
+ return false;
+
+ if (path.elementAt(2).x != x2)
+ return false;
+
+ if (path.elementAt(3).x != x1 || path.elementAt(3).y != y2)
+ return false;
+
+ if (path.elementAt(4).x != x1 || path.elementAt(4).y != y1)
+ return false;
+
+ if (rect)
+ *rect = QRectF(QPointF(x1, y1), QPointF(x2, y2));
+
+ return true;
+}
+
+#endif
+
void QVGPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op)
{
#if !defined(QVG_NO_RENDER_TO_MASK)
Q_D(QVGPaintEngine);
+ // If the path is a simple rectangle, then use clip(QRect) instead.
+ QRectF simpleRect;
+ if (qt_vg_pathToRect(path, &simpleRect)) {
+ clip(simpleRect.toRect(), op);
+ return;
+ }
+
d->dirty |= QPaintEngine::DirtyClipRegion;
if (op == Qt::NoClip) {
@@ -1765,7 +1910,7 @@ void QVGPaintEnginePrivate::ensureMask
maskRect = QRect();
} else {
vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
- if (!maskRect.isNull()) {
+ if (maskRect.isValid()) {
vgMask(VG_INVALID_HANDLE, VG_FILL_MASK,
maskRect.x(), height - maskRect.y() - maskRect.height(),
maskRect.width(), maskRect.height());
@@ -1797,6 +1942,27 @@ void QVGPaintEnginePrivate::modifyMask
maskIsSet = false;
}
+void QVGPaintEnginePrivate::modifyMask
+ (QVGPaintEngine *engine, VGMaskOperation op, const QRect& rect)
+{
+ QPaintDevice *pdev = engine->paintDevice();
+ int width = pdev->width();
+ int height = pdev->height();
+
+ if (!maskValid)
+ ensureMask(engine, width, height);
+
+ if (rect.isValid()) {
+ vgMask(VG_INVALID_HANDLE, op,
+ rect.x(), height - rect.y() - rect.height(),
+ rect.width(), rect.height());
+ }
+
+ vgSeti(VG_MASKING, VG_TRUE);
+ maskValid = true;
+ maskIsSet = false;
+}
+
#endif // !QVG_SCISSOR_CLIP
void QVGPaintEngine::updateScissor()
@@ -1892,6 +2058,16 @@ bool QVGPaintEngine::isDefaultClipRegion(const QRegion& region)
rect.width() == width && rect.height() == height);
}
+bool QVGPaintEngine::isDefaultClipRect(const QRect& rect)
+{
+ QPaintDevice *pdev = paintDevice();
+ int width = pdev->width();
+ int height = pdev->height();
+
+ return (rect.x() == 0 && rect.y() == 0 &&
+ rect.width() == width && rect.height() == height);
+}
+
void QVGPaintEngine::clipEnabledChanged()
{
#if defined(QVG_SCISSOR_CLIP)