summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Nichols <andy.nichols@digia.com>2014-09-08 18:22:45 +0200
committerAndy Nichols <andy.nichols@digia.com>2014-10-21 15:05:34 +0300
commitcc972dc16c5ebcff5e8dc728f98605ad4e899c8c (patch)
tree35e14b6a9ecfed367551cf80989fb06fba1eecc2
parentd2eb3152552846b88d693d5381c5bdbbf395e76c (diff)
Improve quality of RectangleNodes when rotated
When there is a rotation transformation on a RectangleNode it is not possible to take advantage of accelerated blitter paths, but we still need to do custom painting to recreate the behavior of a Rectangle component in Qt Quick. Now when there is a rotaiton transformation we will fall back to using QPainter::drawRect as long as there is no border or radius. If there is a border or radius value set though we will instead first render to a QPixmap before painting as the standard behavior of QPainter::drawRect and QPainter::drawRoundedRect does not match the expected behavior of a QQuick Rectangle item. This fixes the poor quality of rotated Rectangles at the cost of speed. The Rotation of any item should still be discouraged for performance reasons, but at least now Rectangles itmes should look correct when used. Change-Id: I3919ad732c9b4354a95e28e8dc09fcefd53f604e Reviewed-by: Eirik Aavitsland <eirik.aavitsland@digia.com>
-rw-r--r--src/plugins/scenegraph/softwarecontext/rectanglenode.cpp97
-rw-r--r--src/plugins/scenegraph/softwarecontext/rectanglenode.h2
2 files changed, 68 insertions, 31 deletions
diff --git a/src/plugins/scenegraph/softwarecontext/rectanglenode.cpp b/src/plugins/scenegraph/softwarecontext/rectanglenode.cpp
index 0a4fcf8859..b2a14725e8 100644
--- a/src/plugins/scenegraph/softwarecontext/rectanglenode.cpp
+++ b/src/plugins/scenegraph/softwarecontext/rectanglenode.cpp
@@ -22,12 +22,13 @@
#include <QtGui/QPainter>
-
RectangleNode::RectangleNode()
: m_penWidth(0)
, m_radius(0)
, m_cornerPixmapIsDirty(true)
{
+ m_pen.setJoinStyle(Qt::MiterJoin);
+ m_pen.setMiterLimit(0);
setMaterial((QSGMaterial*)1);
setGeometry((QSGGeometry*)1);
}
@@ -232,8 +233,42 @@ void RectangleNode::update()
void RectangleNode::paint(QPainter *painter)
{
+ if (painter->transform().isRotating()) {
+ //Rotated rectangles lose the benefits of direct rendering, and have poor rendering
+ //quality when using only blits and fills.
+
+ if (m_radius == 0 && m_penWidth == 0) {
+ //Non-Rounded Rects without borders (fall back to drawRect)
+ //Most common case
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(m_brush);
+ painter->drawRect(m_rect);
+ } else {
+ //Rounded Rects and Rects with Borders
+ //Avoids broken behaviors of QPainter::drawRect/roundedRect
+ QPixmap pixmap = QPixmap(m_rect.size());
+ pixmap.fill(Qt::transparent);
+ QPainter pixmapPainter(&pixmap);
+ paintRectangle(&pixmapPainter, pixmap.rect());
+
+ QPainter::RenderHints previousRenderHints = painter->renderHints();
+ painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
+ painter->drawPixmap(m_rect, pixmap);
+ painter->setRenderHints(previousRenderHints);
+ }
+
+
+ } else {
+ //Paint directly
+ paintRectangle(painter, m_rect);
+ }
+
+}
+
+void RectangleNode::paintRectangle(QPainter *painter, const QRect &rect)
+{
//Radius should never exceeds half of the width or half of the height
- int radius = qFloor(qMin(qMin(m_rect.width(), m_rect.height()) * 0.5, m_radius));
+ int radius = qFloor(qMin(qMin(rect.width(), rect.height()) * 0.5, m_radius));
QPainter::RenderHints previousRenderHints = painter->renderHints();
painter->setRenderHint(QPainter::Antialiasing, false);
@@ -242,21 +277,21 @@ void RectangleNode::paint(QPainter *painter)
//Fill border Rects
//Borders can not be more than half the height/width of a rect
- double borderWidth = qMin(m_penWidth, m_rect.width() * 0.5);
- double borderHeight = qMin(m_penWidth, m_rect.height() * 0.5);
+ double borderWidth = qMin(m_penWidth, rect.width() * 0.5);
+ double borderHeight = qMin(m_penWidth, rect.height() * 0.5);
if (borderWidth > radius) {
//4 Rects
- QRectF borderTopOutside(QPointF(m_rect.x() + radius, m_rect.y()),
- QPointF(m_rect.x() + m_rect.width() - radius, m_rect.y() + radius));
- QRectF borderTopInside(QPointF(m_rect.x() + borderWidth, m_rect.y() + radius),
- QPointF(m_rect.x() + m_rect.width() - borderWidth, m_rect.y() + borderHeight));
- QRectF borderBottomOutside(QPointF(m_rect.x() + radius, m_rect.y() + m_rect.height() - radius),
- QPointF(m_rect.x() + m_rect.width() - radius, m_rect.y() + m_rect.height()));
- QRectF borderBottomInside(QPointF(m_rect.x() + borderWidth, m_rect.y() + m_rect.height() - borderHeight),
- QPointF(m_rect.x() + m_rect.width() - borderWidth, m_rect.y() + m_rect.height() - radius));
+ QRectF borderTopOutside(QPointF(rect.x() + radius, rect.y()),
+ QPointF(rect.x() + rect.width() - radius, rect.y() + radius));
+ QRectF borderTopInside(QPointF(rect.x() + borderWidth, rect.y() + radius),
+ QPointF(rect.x() + rect.width() - borderWidth, rect.y() + borderHeight));
+ QRectF borderBottomOutside(QPointF(rect.x() + radius, rect.y() + rect.height() - radius),
+ QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height()));
+ QRectF borderBottomInside(QPointF(rect.x() + borderWidth, rect.y() + rect.height() - borderHeight),
+ QPointF(rect.x() + rect.width() - borderWidth, rect.y() + rect.height() - radius));
if (borderTopOutside.isValid())
painter->fillRect(borderTopOutside, m_penColor);
@@ -269,19 +304,19 @@ void RectangleNode::paint(QPainter *painter)
} else {
//2 Rects
- QRectF borderTop(QPointF(m_rect.x() + radius, m_rect.y()),
- QPointF(m_rect.x() + m_rect.width() - radius, m_rect.y() + borderHeight));
- QRectF borderBottom(QPointF(m_rect.x() + radius, m_rect.y() + m_rect.height() - borderHeight),
- QPointF(m_rect.x() + m_rect.width() - radius, m_rect.y() + m_rect.height()));
+ QRectF borderTop(QPointF(rect.x() + radius, rect.y()),
+ QPointF(rect.x() + rect.width() - radius, rect.y() + borderHeight));
+ QRectF borderBottom(QPointF(rect.x() + radius, rect.y() + rect.height() - borderHeight),
+ QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height()));
if (borderTop.isValid())
painter->fillRect(borderTop, m_penColor);
if (borderBottom.isValid())
painter->fillRect(borderBottom, m_penColor);
}
- QRectF borderLeft(QPointF(m_rect.x(), m_rect.y() + radius),
- QPointF(m_rect.x() + borderWidth, m_rect.y() + m_rect.height() - radius));
- QRectF borderRight(QPointF(m_rect.x() + m_rect.width() - borderWidth, m_rect.y() + radius),
- QPointF(m_rect.x() + m_rect.width(), m_rect.y() + m_rect.height() - radius));
+ QRectF borderLeft(QPointF(rect.x(), rect.y() + radius),
+ QPointF(rect.x() + borderWidth, rect.y() + rect.height() - radius));
+ QRectF borderRight(QPointF(rect.x() + rect.width() - borderWidth, rect.y() + radius),
+ QPointF(rect.x() + rect.width(), rect.y() + rect.height() - radius));
if (borderLeft.isValid())
painter->fillRect(borderLeft, m_penColor);
if (borderRight.isValid())
@@ -291,23 +326,23 @@ void RectangleNode::paint(QPainter *painter)
if (radius > 0) {
- if (radius * 2 >= m_rect.width() && radius * 2 >= m_rect.height()) {
+ if (radius * 2 >= rect.width() && radius * 2 >= rect.height()) {
//Blit whole pixmap for circles
- painter->drawPixmap(m_rect, m_cornerPixmap, m_cornerPixmap.rect());
+ painter->drawPixmap(rect, m_cornerPixmap, m_cornerPixmap.rect());
} else {
//blit 4 corners to border
- QRectF topLeftCorner(QPointF(m_rect.x(), m_rect.y()),
- QPointF(m_rect.x() + radius, m_rect.y() + radius));
+ QRectF topLeftCorner(QPointF(rect.x(), rect.y()),
+ QPointF(rect.x() + radius, rect.y() + radius));
painter->drawPixmap(topLeftCorner, m_cornerPixmap, QRectF(0, 0, radius, radius));
- QRectF topRightCorner(QPointF(m_rect.x() + m_rect.width() - radius, m_rect.y()),
- QPointF(m_rect.x() + m_rect.width(), m_rect.y() + radius));
+ QRectF topRightCorner(QPointF(rect.x() + rect.width() - radius, rect.y()),
+ QPointF(rect.x() + rect.width(), rect.y() + radius));
painter->drawPixmap(topRightCorner, m_cornerPixmap, QRectF(radius, 0, radius, radius));
- QRectF bottomLeftCorner(QPointF(m_rect.x(), m_rect.y() + m_rect.height() - radius),
- QPointF(m_rect.x() + radius, m_rect.y() + m_rect.height()));
+ QRectF bottomLeftCorner(QPointF(rect.x(), rect.y() + rect.height() - radius),
+ QPointF(rect.x() + radius, rect.y() + rect.height()));
painter->drawPixmap(bottomLeftCorner, m_cornerPixmap, QRectF(0, radius, radius, radius));
- QRectF bottomRightCorner(QPointF(m_rect.x() + m_rect.width() - radius, m_rect.y() + m_rect.height() - radius),
- QPointF(m_rect.x() + m_rect.width(), m_rect.y() + m_rect.height()));
+ QRectF bottomRightCorner(QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height() - radius),
+ QPointF(rect.x() + rect.width(), rect.y() + rect.height()));
painter->drawPixmap(bottomRightCorner, m_cornerPixmap, QRectF(radius, radius, radius, radius));
}
@@ -315,7 +350,7 @@ void RectangleNode::paint(QPainter *painter)
}
int penWidth = qRound(m_penWidth);
- QRectF brushRect = m_rect.marginsRemoved(QMargins(penWidth, penWidth, penWidth, penWidth));
+ QRectF brushRect = rect.marginsRemoved(QMargins(penWidth, penWidth, penWidth, penWidth));
if (brushRect.width() < 0)
brushRect.setWidth(0);
if (brushRect.height() < 0)
diff --git a/src/plugins/scenegraph/softwarecontext/rectanglenode.h b/src/plugins/scenegraph/softwarecontext/rectanglenode.h
index f4c7cb3dcf..d3bcb2b8dc 100644
--- a/src/plugins/scenegraph/softwarecontext/rectanglenode.h
+++ b/src/plugins/scenegraph/softwarecontext/rectanglenode.h
@@ -45,6 +45,8 @@ public:
void paint(QPainter *);
private:
+ void paintRectangle(QPainter *painter, const QRect &rect);
+
QRect m_rect;
QColor m_color;
QColor m_penColor;