summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-19 12:12:35 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-09-29 13:16:36 +0200
commit81008ef4b91eac3f8ddcdad0aaf48b51135c4010 (patch)
tree6a75d61eaef253e3e9644aef7ea80346899c16e0 /src/gui
parent19a95c5e212c3f83e1338daf2df0fd23f9582c84 (diff)
Reimplement non-antialiased cosmetic pen
Simplify rounding to get rid of hacks to make lines meet up again. This also results in better looking drawing results in general. Task-number: QTBUG-25896 Change-Id: I48f08f0e7bd7ff869d6767f7bac2a18c2d280615 Reviewed-by: Gatis Paeglis <gatis.paeglis@qt.io>
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/painting/qcosmeticstroker.cpp291
1 files changed, 98 insertions, 193 deletions
diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp
index 001c44696a..aec672be5b 100644
--- a/src/gui/painting/qcosmeticstroker.cpp
+++ b/src/gui/painting/qcosmeticstroker.cpp
@@ -594,45 +594,50 @@ void QCosmeticStroker::drawPath(const QVectorPath &path)
lastPixel.x = INT_MIN;
lastPixel.y = INT_MIN;
- const qreal *begin = points;
- const qreal *end = points + 2*path.elementCount();
- // handle closed path case
- bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]);
- int caps = (!closed && drawCaps) ? CapBegin : NoCaps;
- if (closed) {
- 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());
- }
+ if (path.elementCount() > 2) {
+ const qreal *begin = points;
+ const qreal *end = points + 2*path.elementCount();
+ // handle closed path case
+ bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]);
+ int caps = (!closed && drawCaps) ? CapBegin : NoCaps;
+ if (closed) {
+ QPointF p2;
+ if (points[0] == end[-2] && points[1] == end[-1])
+ 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());
+ }
- bool fastPenAliased = (state->flags.fast_pen && !state->flags.antialiased);
- points += 2;
- while (points < end) {
- QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
+ bool fastPenAliased = (state->flags.fast_pen && !state->flags.antialiased);
+ points += 2;
+ while (points < end) {
+ QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
- if (!closed && drawCaps && points == end - 2)
- caps |= CapEnd;
+ if (!closed && drawCaps && points == end - 2)
+ caps |= CapEnd;
- bool moveNextStart = stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps);
+ bool moveNextStart = stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps);
- /* fix for gaps in polylines with fastpen and aliased in a sequence
- of points with small distances: if current point p2 has been dropped
- out, keep last non dropped point p.
+ /* fix for gaps in polylines with fastpen and aliased in a sequence
+ of points with small distances: if current point p2 has been dropped
+ out, keep last non dropped point p.
- However, if the line was completely outside the devicerect, we
- still need to update p to avoid drawing the line after this one from
- a bad starting position.
- */
- if (!fastPenAliased || moveNextStart || points == begin + 2 || points == end - 2)
- p = p2;
- points += 2;
- caps = NoCaps;
+ However, if the line was completely outside the devicerect, we
+ still need to update p to avoid drawing the line after this one from
+ a bad starting position.
+ */
+ if (!fastPenAliased || moveNextStart || points == begin + 2 || points == end - 2)
+ p = p2;
+ points += 2;
+ caps = NoCaps;
+ }
+ if (path.hasImplicitClose())
+ stroke(this, p.x(), p.y(), movedTo.x(), movedTo.y(), NoCaps);
+ } else {
+ // A line...
+ stroke(this, points[0], points[1], points[2], points[3], CapBegin | CapEnd);
}
- if (path.hasImplicitClose())
- stroke(this, p.x(), p.y(), movedTo.x(), movedTo.y(), NoCaps);
}
@@ -744,98 +749,48 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
int x2 = toF26Dot6(rx2) + half;
int y2 = toF26Dot6(ry2) + half;
- int dx = qAbs(x2 - x1);
- int dy = qAbs(y2 - y1);
-
QCosmeticStroker::Point last = stroker->lastPixel;
// 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) {
- swapped = true;
- qSwap(y1, y2);
- qSwap(x1, x2);
- caps = swapCaps(caps);
- dir = QCosmeticStroker::BottomToTop;
- }
- int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
- int x = x1 * (1<<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 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++;
+ int yi = y1 >> 6;
+ int ys = y2 >> 6;
+ int xi = x1 >> 6;
+ int xs = x2 >> 6;
+ const int dx = qAbs(xs - xi);
+ const int dy = qAbs(ys - yi);
+ last.x = xs;
+ last.y = ys;
+ if (dx < dy) {
+ int y = yi;
if (y != ys) {
- x += ((y * (1<<6)) + round - y1) * xinc >> 6;
-
- // calculate first and last pixel and perform dropout control
- QCosmeticStroker::Point first;
- first.x = x >> 16;
- first.y = y;
- last.x = (x + (ys - y - 1)*xinc) >> 16;
- last.y = ys - 1;
- if (swapped)
- qSwap(first, last);
-
- bool axisAligned = qAbs(xinc) < (1 << 14);
- if (stroker->lastPixel.x > INT_MIN) {
- if (first.x == stroker->lastPixel.x &&
- first.y == stroker->lastPixel.y) {
- // remove duplicated pixel
- if (swapped) {
- --ys;
- } else {
- ++y;
- x += xinc;
- }
- } 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.y - first.y) > 1))) {
- // have a missing pixel, insert it
- if (swapped) {
- ++ys;
- } else {
- --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;
+ const int xinc = F16Dot16FixedDiv(x2 - x1, ys - yi) >> 6;
+ Q_ASSERT(xinc <= 0x10000);
+ int x = x1 * (1<<10);
+
+ Dasher dasher(stroker, y > ys, y * (1<<6), ys * (1<<6));
+
+ if (ys > y) {
+ for (; y < ys; ++y) {
+ if (dasher.on())
+ drawPixel(stroker, x >> 16, y, 255);
+ dasher.adjust();
+ x += xinc;
+ }
+ } else {
+ for (; y > ys; --y) {
+ if (dasher.on())
+ drawPixel(stroker, x >> 16, y, 255);
+ dasher.adjust();
+ x -= xinc;
}
}
- stroker->lastDir = dir;
- stroker->lastAxisAligned = axisAligned;
-
- Dasher dasher(stroker, swapped, y * (1<<6), ys * (1<<6));
-
- do {
+ if (caps & QCosmeticStroker::CapEnd) {
+ Q_ASSERT(y == ys);
if (dasher.on())
- drawPixel(stroker, x >> 16, y, 255);
- dasher.adjust();
- x += xinc;
- } while (++y < ys);
+ drawPixel(stroker, xs, ys, 255);
+ }
didDraw = true;
}
} else {
@@ -843,88 +798,38 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
if (!dx)
return true;
- QCosmeticStroker::Direction dir = QCosmeticStroker::LeftToRight;
-
- bool swapped = false;
- if (x1 > x2) {
- swapped = true;
- qSwap(x1, x2);
- qSwap(y1, y2);
- caps = swapCaps(caps);
- dir = QCosmeticStroker::RightToLeft;
- }
- int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
- int y = y1 * (1<<10);
-
- if ((stroker->lastDir ^ QCosmeticStroker::HorizontalMask) == dir)
- caps |= swapped ? QCosmeticStroker::CapEnd : QCosmeticStroker::CapBegin;
-
- capAdjust(caps, x1, x2, y, yinc);
-
- int x = (x1 + 32) >> 6;
- 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++;
-
+ int x = xi;
if (x != xs) {
- y += ((x * (1<<6)) + round - x1) * yinc >> 6;
-
- // calculate first and last pixel to perform dropout control
- QCosmeticStroker::Point first;
- first.x = x;
- first.y = y >> 16;
- last.x = xs - 1;
- last.y = (y + (xs - x - 1)*yinc) >> 16;
- if (swapped)
- qSwap(first, last);
-
- bool axisAligned = qAbs(yinc) < (1 << 14);
- if (stroker->lastPixel.x > INT_MIN) {
- if (first.x == stroker->lastPixel.x && first.y == stroker->lastPixel.y) {
- // remove duplicated pixel
- if (swapped) {
- --xs;
- } else {
- ++x;
- y += yinc;
- }
- } 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.y - first.y) > 1))) {
- // have a missing pixel, insert it
- if (swapped) {
- ++xs;
- } else {
- --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;
- }
+ int y = y1 * (1<<10);
+ int yinc = F16Dot16FixedDiv(y2 - y1, xs - xi) >> 6;
+ if (yinc > 0x10000) {
+ yinc = F16Dot16FixedDiv(ys - yi, xs - xi);
+ y = yi * (1<<16);
}
- stroker->lastDir = dir;
- stroker->lastAxisAligned = axisAligned;
+ Q_ASSERT(yinc <= 0x10000);
- Dasher dasher(stroker, swapped, x * (1<<6), xs * (1<<6));
+ Dasher dasher(stroker, x > xs, x * (1<<6), xs * (1<<6));
- do {
+ if (xs > x) {
+ do {
+ if (dasher.on())
+ drawPixel(stroker, x, y >> 16, 255);
+ dasher.adjust();
+ y += yinc;
+ } while (++x < xs);
+ } else {
+ do {
+ if (dasher.on())
+ drawPixel(stroker, x, y >> 16, 255);
+ dasher.adjust();
+ y -= yinc;
+ } while (--x > xs);
+ }
+ if (caps & QCosmeticStroker::CapEnd) {
+ Q_ASSERT(x == xs);
if (dasher.on())
- drawPixel(stroker, x, y >> 16, 255);
- dasher.adjust();
- y += yinc;
- } while (++x < xs);
+ drawPixel(stroker, xs, ys, 255);
+ }
didDraw = true;
}
}