Correctly position aliased lines with flat caps
authorLars Knoll <lars.knoll@nokia.com>
Fri, 19 Aug 2011 09:58:18 +0000 (11:58 +0200)
committerQt by Nokia <qt-info@nokia.com>
Wed, 31 Aug 2011 11:12:43 +0000 (13:12 +0200)
The code was mispositioning lines by half a pixel, as it
added half a pixel offset and then rounded in addition.
This submit fixes this and also removes certain artifacts when
drawing rects at .5 pixel positions.

Lance now doesn't show any significant differences to the
4.7 rendering anymore.

Task-number: QTBUG-20199
Reviewed-by: Aavit
(cherry picked from commit 49409f612c47f30434aa809e4d2c963f1a6bb88a)

Change-Id: Iab3936e688eba16b82f5cdb4f36f54af807d78ea
Reviewed-on: http://codereview.qt.nokia.com/3260
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
src/gui/painting/qcosmeticstroker.cpp
src/gui/painting/qcosmeticstroker_p.h

index dbe957e..3528e6f 100644 (file)
@@ -425,13 +425,12 @@ void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal
             swapped = true;
             qSwap(y1, y2);
             qSwap(x1, x2);
-            --x1; --x2; --y1; --y2;
         }
         int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
         int x = x1 << 10;
 
-        int y = (y1+32) >> 6;
-        int ys = (y2+32) >> 6;
+        int y = y1 >> 6;
+        int ys = y2 >> 6;
 
         if (y != ys) {
             x += ( ((((y << 6) + 32 - y1)))  * xinc ) >> 6;
@@ -457,13 +456,12 @@ void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal
             swapped = true;
             qSwap(x1, x2);
             qSwap(y1, y2);
-            --x1; --x2; --y1; --y2;
         }
         int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
         int y = y1 << 10;
 
-        int x = (x1+32) >> 6;
-        int xs = (x2+32) >> 6;
+        int x = x1 >> 6;
+        int xs = x2 >> 6;
 
         if (x != xs) {
             y += ( ((((x << 6) + 32 - x1)))  * yinc ) >> 6;
@@ -716,10 +714,11 @@ static void drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
 
     QCosmeticStroker::Point last = stroker->lastPixel;
 
-//    qDebug() << "stroke" << x1/64. << y1/64. << x2/64. << y2/64. << capString(caps);
+//    qDebug() << "stroke" << x1/64. << y1/64. << x2/64. << y2/64.;
 
     if (dx < dy) {
         // vertical
+        QCosmeticStroker::Direction dir = QCosmeticStroker::TopToBottom;
 
         bool swapped = false;
         if (y1 > y2) {
@@ -727,30 +726,31 @@ static void drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
             qSwap(y1, y2);
             qSwap(x1, x2);
             caps = swapCaps(caps);
-            --x1; --x2; --y1; --y2;
+            dir = QCosmeticStroker::BottomToTop;
         }
         int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
         int x = x1 << 10;
 
+        if ((stroker->lastDir ^ QCosmeticStroker::VerticalMask) == dir)
+            caps |= swapped ? QCosmeticStroker::CapEnd : QCosmeticStroker::CapBegin;
+
         capAdjust(caps, y1, y2, x, xinc);
 
-        int y = (y1+32) >> 6;
-        int ys = (y2+32) >> 6;
+        int y = y1 >> 6;
+        int ys = y2 >> 6;
 
         if (y != ys) {
             x += ( ((((y << 6) + 32 - y1)))  * xinc ) >> 6;
 
             // calculate first and last pixel and perform dropout control
-            QCosmeticStroker::Direction dir = QCosmeticStroker::TopToBottom;
             QCosmeticStroker::Point first;
             first.x = x >> 16;
             first.y = y;
             last.x = (x + (ys - y - 1)*xinc) >> 16;
             last.y = ys - 1;
-            if (swapped) {
+            if (swapped)
                 qSwap(first, last);
-                dir = QCosmeticStroker::BottomToTop;
-            }
+
             bool axisAligned = qAbs(xinc) < (1 << 14);
             if (stroker->lastPixel.x >= 0) {
                 if (first.x == stroker->lastPixel.x &&
@@ -765,7 +765,7 @@ static void drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
                 } else if (stroker->lastDir != dir &&
                            (((axisAligned && stroker->lastAxisAligned) &&
                              stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
-                            (qAbs(stroker->lastPixel.x - first.x) > 1 &&
+                            (qAbs(stroker->lastPixel.x - first.x) > 1 ||
                              qAbs(stroker->lastPixel.y - first.y) > 1))) {
                     // have a missing pixel, insert it
                     if (swapped) {
@@ -793,37 +793,39 @@ static void drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
         if (!dx)
             return;
 
+        QCosmeticStroker::Direction dir = QCosmeticStroker::LeftToRight;
+
         bool swapped = false;
         if (x1 > x2) {
             swapped = true;
             qSwap(x1, x2);
             qSwap(y1, y2);
             caps = swapCaps(caps);
-            --x1; --x2; --y1; --y2;
+            dir = QCosmeticStroker::RightToLeft;
         }
         int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
         int y = y1 << 10;
 
-        capAdjust(caps, x1, x2, y, yinc);
+        if ((stroker->lastDir ^ QCosmeticStroker::HorizontalMask) == dir)
+            caps |= swapped ? QCosmeticStroker::CapEnd : QCosmeticStroker::CapBegin;
 
-        int x = (x1+32) >> 6;
-        int xs = (x2+32) >> 6;
+        capAdjust(caps, x1, x2, y, yinc);
 
+        int x = x1 >> 6;
+        int xs = x2 >> 6;
 
         if (x != xs) {
             y += ( ((((x << 6) + 32 - x1)))  * yinc ) >> 6;
 
             // calculate first and last pixel to perform dropout control
-            QCosmeticStroker::Direction dir = QCosmeticStroker::LeftToRight;
             QCosmeticStroker::Point first;
             first.x = x;
             first.y = y >> 16;
             last.x = xs - 1;
             last.y = (y + (xs - x - 1)*yinc) >> 16;
-            if (swapped) {
+            if (swapped)
                 qSwap(first, last);
-                dir = QCosmeticStroker::RightToLeft;
-            }
+
             bool axisAligned = qAbs(yinc) < (1 << 14);
             if (stroker->lastPixel.x >= 0) {
                 if (first.x == stroker->lastPixel.x && first.y == stroker->lastPixel.y) {
@@ -837,7 +839,7 @@ static void drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
                 } else if (stroker->lastDir != dir &&
                            (((axisAligned && stroker->lastAxisAligned) &&
                              stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
-                            (qAbs(stroker->lastPixel.x - first.x) > 1 &&
+                            (qAbs(stroker->lastPixel.x - first.x) > 1 ||
                              qAbs(stroker->lastPixel.y - first.y) > 1))) {
                     // have a missing pixel, insert it
                     if (swapped) {
index d7bd79a..53cdf2c 100644 (file)
@@ -78,10 +78,12 @@ public:
 
     // used to avoid drop outs or duplicated points
     enum Direction {
-        TopToBottom,
-        BottomToTop,
-        LeftToRight,
-        RightToLeft
+        TopToBottom = 0x1,
+        BottomToTop = 0x2,
+        LeftToRight = 0x4,
+        RightToLeft = 0x8,
+        VerticalMask = 0x3,
+        HorizontalMask = 0xc
     };
 
     QCosmeticStroker(QRasterPaintEngineState *s, const QRect &dr)