summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/painting/qcosmeticstroker.cpp56
-rw-r--r--tests/auto/gui/painting/qpainter/tst_qpainter.cpp108
2 files changed, 151 insertions, 13 deletions
diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp
index 4965762d74..bcb243db6a 100644
--- a/src/gui/painting/qcosmeticstroker.cpp
+++ b/src/gui/painting/qcosmeticstroker.cpp
@@ -304,8 +304,8 @@ void QCosmeticStroker::setup()
ymin = deviceRect.top() - 1;
ymax = deviceRect.bottom() + 2;
- lastPixel.x = -1;
- lastPixel.y = -1;
+ lastPixel.x = INT_MIN;
+ lastPixel.y = INT_MIN;
}
// returns true if the whole line gets clipped away
@@ -325,11 +325,11 @@ bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
x1 = xmax;
}
if (x2 < xmin) {
- lastPixel.x = -1;
+ lastPixel.x = INT_MIN;
y2 += (y2 - y1)/(x2 - x1) * (xmin - x2);
x2 = xmin;
} else if (x2 > xmax) {
- lastPixel.x = -1;
+ lastPixel.x = INT_MIN;
y2 += (y2 - y1)/(x2 - x1) * (xmax - x2);
x2 = xmax;
}
@@ -346,11 +346,11 @@ bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
y1 = ymax;
}
if (y2 < ymin) {
- lastPixel.x = -1;
+ lastPixel.x = INT_MIN;
x2 += (x2 - x1)/(y2 - y1) * (ymin - y2);
y2 = ymin;
} else if (y2 > ymax) {
- lastPixel.x = -1;
+ lastPixel.x = INT_MIN;
x2 += (x2 - x1)/(y2 - y1) * (ymax - y2);
y2 = ymax;
}
@@ -358,7 +358,7 @@ bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
return false;
clipped:
- lastPixel.x = -1;
+ lastPixel.x = INT_MIN;
return true;
}
@@ -374,7 +374,7 @@ void QCosmeticStroker::drawLine(const QPointF &p1, const QPointF &p2)
QPointF end = p2 * state->matrix;
patternOffset = state->lastPen.dashOffset()*64;
- lastPixel.x = -1;
+ lastPixel.x = INT_MIN;
stroke(this, start.x(), start.y(), end.x(), end.y(), drawCaps ? CapBegin|CapEnd : 0);
@@ -417,8 +417,8 @@ void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal
// by calculating the direction and last pixel of the last segment in the contour.
// the info is then used to perform dropout control when drawing the first line segment
// of the contour
- lastPixel.x = -1;
- lastPixel.y = -1;
+ lastPixel.x = INT_MIN;
+ lastPixel.y = INT_MIN;
if (clipLine(rx1, ry1, rx2, ry2))
return;
@@ -599,7 +599,11 @@ void QCosmeticStroker::drawPath(const QVectorPath &path)
bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]);
int caps = (!closed && drawCaps) ? CapBegin : NoCaps;
if (closed) {
- QPointF p2 = QPointF(end[-2], end[-1]) * state->matrix;
+ QPointF p2;
+ if (points[0] == end[-2] && points[1] == end[-1] && path.elementCount() > 2)
+ p2 = QPointF(end[-4], end[-3]) * state->matrix;
+ else
+ p2 = QPointF(end[-2], end[-1]) * state->matrix;
calculateLastPoint(p2.x(), p2.y(), p.x(), p.y());
}
@@ -770,6 +774,11 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
int ys = (y2 + 32) >> 6;
int round = (xinc > 0) ? 32 : 0;
+ // If capAdjust made us round away from what calculateLastPoint gave us,
+ // round back the other way so we start and end on the right point.
+ if ((caps & QCosmeticStroker::CapBegin) && stroker->lastPixel.y == y + 1)
+ y++;
+
if (y != ys) {
x += ((y * (1<<6)) + round - y1) * xinc >> 6;
@@ -783,7 +792,7 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
qSwap(first, last);
bool axisAligned = qAbs(xinc) < (1 << 14);
- if (stroker->lastPixel.x >= 0) {
+ if (stroker->lastPixel.x > INT_MIN) {
if (first.x == stroker->lastPixel.x &&
first.y == stroker->lastPixel.y) {
// remove duplicated pixel
@@ -805,6 +814,14 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
--y;
x -= xinc;
}
+ } else if (stroker->lastDir == dir &&
+ ((qAbs(stroker->lastPixel.x - first.x) <= 1 &&
+ qAbs(stroker->lastPixel.y - first.y) > 1))) {
+ x += xinc >> 1;
+ if (swapped)
+ last.x = (x >> 16);
+ else
+ last.x = (x + (ys - y - 1)*xinc) >> 16;
}
}
stroker->lastDir = dir;
@@ -847,6 +864,11 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
int xs = (x2 + 32) >> 6;
int round = (yinc > 0) ? 32 : 0;
+ // If capAdjust made us round away from what calculateLastPoint gave us,
+ // round back the other way so we start and end on the right point.
+ if ((caps & QCosmeticStroker::CapBegin) && stroker->lastPixel.x == x + 1)
+ x++;
+
if (x != xs) {
y += ((x * (1<<6)) + round - x1) * yinc >> 6;
@@ -860,7 +882,7 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
qSwap(first, last);
bool axisAligned = qAbs(yinc) < (1 << 14);
- if (stroker->lastPixel.x >= 0) {
+ if (stroker->lastPixel.x > INT_MIN) {
if (first.x == stroker->lastPixel.x && first.y == stroker->lastPixel.y) {
// remove duplicated pixel
if (swapped) {
@@ -881,6 +903,14 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
--x;
y -= yinc;
}
+ } else if (stroker->lastDir == dir &&
+ ((qAbs(stroker->lastPixel.x - first.x) <= 1 &&
+ qAbs(stroker->lastPixel.y - first.y) > 1))) {
+ y += yinc >> 1;
+ if (swapped)
+ last.y = (y >> 16);
+ else
+ last.y = (y + (xs - x - 1)*yinc) >> 16;
}
}
stroker->lastDir = dir;
diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
index 8db4489ec1..6b6869c2ba 100644
--- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
+++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
@@ -303,6 +303,8 @@ private slots:
void blendNullRGB32();
void toRGB64();
+ void fillPolygon();
+
private:
void fillData();
void setPenColor(QPainter& p);
@@ -5191,6 +5193,112 @@ void tst_QPainter::toRGB64()
}
}
+void tst_QPainter::fillPolygon()
+{
+ QImage image(50, 50, QImage::Format_RGB32);
+ image.fill(Qt::white);
+
+ QPainter painter(&image);
+ QBrush brush(Qt::black, Qt::SolidPattern);
+ painter.setBrush(brush);
+
+ QPen pen(Qt::red, 0, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
+ painter.setPen(pen);
+
+ const QPoint diamondpoints[5] = {
+ QPoint(-15, 0),
+ QPoint(0, -15),
+ QPoint(15, 0),
+ QPoint(0, 15),
+ QPoint(-15, 0)
+ };
+ enum { Outside1, Border1, Inside, Border2, Outside2 } state;
+
+ for (int i = 0; i < 16 ; i++)
+ {
+ for (int j = 0; j < 16 ; j++)
+ {
+ image.fill(Qt::white);
+ painter.resetTransform();
+ painter.translate(25 + i/16., 25 + j/16.);
+ painter.drawPolygon(diamondpoints, 5);
+
+ for (int x = 0; x < 50; x++) {
+ state = Outside1;
+ for (int y = 0; y < 50; y++) {
+ QRgb c = image.pixel(x, y);
+ switch (state) {
+ case Outside1:
+ if (c == QColor(Qt::red).rgb())
+ state = Border1;
+ else
+ QCOMPARE(c, QColor(Qt::white).rgb());
+ break;
+ case Border1:
+ if (c == QColor(Qt::black).rgb())
+ state = Inside;
+ else if (c == QColor(Qt::white).rgb())
+ state = Outside2;
+ else
+ QCOMPARE(c, QColor(Qt::red).rgb());
+ break;
+ case Inside:
+ if (c == QColor(Qt::red).rgb())
+ state = Border2;
+ else
+ QCOMPARE(c, QColor(Qt::black).rgb());
+ break;
+ case Border2:
+ if (c == QColor(Qt::white).rgb())
+ state = Outside2;
+ else
+ QCOMPARE(c, QColor(Qt::red).rgb());
+ break;
+ case Outside2:
+ QCOMPARE(c, QColor(Qt::white).rgb());
+ }
+ }
+ }
+ for (int y = 0; y < 50; y++) {
+ state = Outside1;
+ for (int x = 0; x < 50; x++) {
+ QRgb c = image.pixel(x, y);
+ switch (state) {
+ case Outside1:
+ if (c == QColor(Qt::red).rgb())
+ state = Border1;
+ else
+ QCOMPARE(c, QColor(Qt::white).rgb());
+ break;
+ case Border1:
+ if (c == QColor(Qt::black).rgb())
+ state = Inside;
+ else if (c == QColor(Qt::white).rgb())
+ state = Outside2;
+ else
+ QCOMPARE(c, QColor(Qt::red).rgb());
+ break;
+ case Inside:
+ if (c == QColor(Qt::red).rgb())
+ state = Border2;
+ else
+ QCOMPARE(c, QColor(Qt::black).rgb());
+ break;
+ case Border2:
+ if (c == QColor(Qt::white).rgb())
+ state = Outside2;
+ else
+ QCOMPARE(c, QColor(Qt::red).rgb());
+ break;
+ case Outside2:
+ QCOMPARE(c, QColor(Qt::white).rgb());
+ }
+ }
+ }
+ }
+ }
+}
+
QTEST_MAIN(tst_QPainter)
#include "tst_qpainter.moc"