diff options
-rw-r--r-- | src/gui/painting/qcosmeticstroker.cpp | 56 | ||||
-rw-r--r-- | tests/auto/gui/painting/qpainter/tst_qpainter.cpp | 108 |
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" |