diff options
author | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-07-02 00:36:19 (GMT) |
---|---|---|
committer | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-07-02 00:36:19 (GMT) |
commit | 0b5c4c4352d0419113cf152b7ae5bbee5a45fd5c (patch) | |
tree | 16bcfc855db378eb31db6b5c6c30f2cec8b3dd79 /src/openvg | |
parent | f31d2c01e5998a9fcf4345fa66e0349921e115da (diff) | |
download | Qt-0b5c4c4352d0419113cf152b7ae5bbee5a45fd5c.zip Qt-0b5c4c4352d0419113cf152b7ae5bbee5a45fd5c.tar.gz Qt-0b5c4c4352d0419113cf152b7ae5bbee5a45fd5c.tar.bz2 |
OpenVG: override QPaintEngineEx::clip(QRect) and handle specially.
This change should improve performance of single-rectangle clip regions
by avoiding the overhead of creating and intersecting QRegion objects.
Task-number: QT-64
Reviewed-by: trustme
Diffstat (limited to 'src/openvg')
-rw-r--r-- | src/openvg/qpaintengine_vg.cpp | 130 | ||||
-rw-r--r-- | src/openvg/qpaintengine_vg_p.h | 1 |
2 files changed, 129 insertions, 2 deletions
diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index 8ce3f69..48953ac 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 ®ion, 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. @@ -1765,7 +1860,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 +1892,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 +2008,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) diff --git a/src/openvg/qpaintengine_vg_p.h b/src/openvg/qpaintengine_vg_p.h index a390c80..bde06e5 100644 --- a/src/openvg/qpaintengine_vg_p.h +++ b/src/openvg/qpaintengine_vg_p.h @@ -154,6 +154,7 @@ private: void updateScissor(); QRegion defaultClipRegion(); bool isDefaultClipRegion(const QRegion& region); + bool isDefaultClipRect(const QRect& rect); bool clearRect(const QRectF &rect, const QColor &color); }; |