diff options
Diffstat (limited to 'src/gui/painting')
-rw-r--r-- | src/gui/painting/qrasterizer.cpp | 178 |
1 files changed, 95 insertions, 83 deletions
diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp index c92d8d5..9d89b10 100644 --- a/src/gui/painting/qrasterizer.cpp +++ b/src/gui/painting/qrasterizer.cpp @@ -65,6 +65,12 @@ typedef int Q16Dot16; #define COORD_ROUNDING 0 // 0: round up, 1: round down #define COORD_OFFSET 0 // 26.6, 32 is half a pixel +static inline QT_FT_Vector PointToVector(const QPointF &p) +{ + QT_FT_Vector result = { QT_FT_Pos(p.x() * 64), QT_FT_Pos(p.y() * 64) }; + return result; +} + class QSpanBuffer { public: QSpanBuffer(ProcessSpans blend, void *data, const QRect &clipRect) @@ -693,9 +699,9 @@ static Q16Dot16 intersectPixelFP(int x, Q16Dot16 top, Q16Dot16 bottom, Q16Dot16 } } -static inline bool q16Dot16Compare(qreal p1, qreal p2) +static inline bool q26Dot6Compare(qreal p1, qreal p2) { - return FloatToQ16Dot16(p2 - p1) == 0; + return int((p2 - p1) * 64.) == 0; } static inline qreal qFloorF(qreal v) @@ -708,6 +714,12 @@ static inline qreal qFloorF(qreal v) return floor(v); } +static inline QPointF snapTo26Dot6Grid(const QPointF &p) +{ + return QPointF(qFloorF(p.x() * 64) * (1 / qreal(64)), + qFloorF(p.y() * 64) * (1 / qreal(64))); +} + void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, bool squareCap) { if (a == b || width == 0 || d->clipRect.isEmpty()) @@ -718,17 +730,21 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, QPointF pa = a; QPointF pb = b; + if (squareCap) { + QPointF delta = pb - pa; + pa -= (0.5f * width) * delta; + pb += (0.5f * width) * delta; + } + QPointF offs = QPointF(qAbs(b.y() - a.y()), qAbs(b.x() - a.x())) * width * 0.5; - if (squareCap) - offs += QPointF(offs.y(), offs.x()); const QRectF clip(d->clipRect.topLeft() - offs, d->clipRect.bottomRight() + QPoint(1, 1) + offs); - if (!clip.contains(a) || !clip.contains(b)) { + if (!clip.contains(pa) || !clip.contains(pb)) { qreal t1 = 0; qreal t2 = 1; - const qreal o[2] = { a.x(), a.y() }; - const qreal d[2] = { b.x() - a.x(), b.y() - a.y() }; + const qreal o[2] = { pa.x(), pa.y() }; + const qreal d[2] = { pb.x() - pa.x(), pb.y() - pa.y() }; const qreal low[2] = { clip.left(), clip.top() }; const qreal high[2] = { clip.right(), clip.bottom() }; @@ -751,8 +767,12 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, if (t1 >= t2) return; } - pa = a + (b - a) * t1; - pb = a + (b - a) * t2; + + QPointF npa = pa + (pb - pa) * t1; + QPointF npb = pa + (pb - pa) * t2; + + pa = npa; + pb = npb; } if (!d->antialiased) { @@ -763,15 +783,6 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, } { - const qreal gridResolution = 64; - const qreal reciprocal = 1 / gridResolution; - - // snap to grid to prevent large slopes - pa.rx() = qFloorF(pa.rx() * gridResolution) * reciprocal; - pa.ry() = qFloorF(pa.ry() * gridResolution) * reciprocal; - pb.rx() = qFloorF(pb.rx() * gridResolution) * reciprocal; - pb.ry() = qFloorF(pb.ry() * gridResolution) * reciprocal; - // old delta const QPointF d0 = a - b; const qreal w0 = d0.x() * d0.x() + d0.y() * d0.y(); @@ -789,7 +800,7 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, QSpanBuffer buffer(d->blend, d->data, d->clipRect); - if (q16Dot16Compare(pa.y(), pb.y())) { + if (q26Dot6Compare(pa.y(), pb.y())) { const qreal x = (pa.x() + pb.x()) * 0.5f; const qreal dx = qAbs(pb.x() - pa.x()) * 0.5f; @@ -799,26 +810,16 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, pa = QPointF(x, y - dy); pb = QPointF(x, y + dy); - if (squareCap) - width = 1 / width + 1.0f; - else - width = 1 / width; - - squareCap = false; + width = 1 / width; } - if (q16Dot16Compare(pa.x(), pb.x())) { + if (q26Dot6Compare(pa.x(), pb.x())) { if (pa.y() > pb.y()) qSwap(pa, pb); const qreal dy = pb.y() - pa.y(); const qreal halfWidth = 0.5f * width * dy; - if (squareCap) { - pa.ry() -= halfWidth; - pb.ry() += halfWidth; - } - qreal left = pa.x() - halfWidth; qreal right = pa.x() + halfWidth; @@ -828,7 +829,7 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, pa.ry() = qBound(qreal(d->clipRect.top()), pa.y(), qreal(d->clipRect.bottom() + 1)); pb.ry() = qBound(qreal(d->clipRect.top()), pb.y(), qreal(d->clipRect.bottom() + 1)); - if (q16Dot16Compare(left, right) || q16Dot16Compare(pa.y(), pb.y())) + if (q26Dot6Compare(left, right) || q26Dot6Compare(pa.y(), pb.y())) return; if (d->antialiased) { @@ -899,11 +900,6 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, delta *= 0.5f * width; const QPointF perp(delta.y(), -delta.x()); - if (squareCap) { - pa -= delta; - pb += delta; - } - QPointF top; QPointF left; QPointF right; @@ -921,14 +917,36 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, bottom = pb + perp; } + top = snapTo26Dot6Grid(top); + bottom = snapTo26Dot6Grid(bottom); + left = snapTo26Dot6Grid(left); + right = snapTo26Dot6Grid(right); + const qreal topBound = qBound(qreal(d->clipRect.top()), top.y(), qreal(d->clipRect.bottom())); const qreal bottomBound = qBound(qreal(d->clipRect.top()), bottom.y(), qreal(d->clipRect.bottom())); - const qreal leftSlope = (left.x() - top.x()) / (left.y() - top.y()); - const qreal rightSlope = -1.0f / leftSlope; + const QPointF topLeftEdge = left - top; + const QPointF topRightEdge = right - top; + const QPointF bottomLeftEdge = bottom - left; + const QPointF bottomRightEdge = bottom - right; + + const qreal topLeftSlope = topLeftEdge.x() / topLeftEdge.y(); + const qreal bottomLeftSlope = bottomLeftEdge.x() / bottomLeftEdge.y(); + + const qreal topRightSlope = topRightEdge.x() / topRightEdge.y(); + const qreal bottomRightSlope = bottomRightEdge.x() / bottomRightEdge.y(); + + const Q16Dot16 topLeftSlopeFP = FloatToQ16Dot16(topLeftSlope); + const Q16Dot16 topRightSlopeFP = FloatToQ16Dot16(topRightSlope); - const Q16Dot16 leftSlopeFP = FloatToQ16Dot16(leftSlope); - const Q16Dot16 rightSlopeFP = FloatToQ16Dot16(rightSlope); + const Q16Dot16 bottomLeftSlopeFP = FloatToQ16Dot16(bottomLeftSlope); + const Q16Dot16 bottomRightSlopeFP = FloatToQ16Dot16(bottomRightSlope); + + const Q16Dot16 invTopLeftSlopeFP = FloatToQ16Dot16(1 / topLeftSlope); + const Q16Dot16 invTopRightSlopeFP = FloatToQ16Dot16(1 / topRightSlope); + + const Q16Dot16 invBottomLeftSlopeFP = FloatToQ16Dot16(1 / bottomLeftSlope); + const Q16Dot16 invBottomRightSlopeFP = FloatToQ16Dot16(1 / bottomRightSlope); if (d->antialiased) { const Q16Dot16 iTopFP = IntToQ16Dot16(int(topBound)); @@ -936,16 +954,16 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, const Q16Dot16 iRightFP = IntToQ16Dot16(int(right.y())); const Q16Dot16 iBottomFP = IntToQ16Dot16(int(bottomBound)); - Q16Dot16 leftIntersectAf = FloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * leftSlope); - Q16Dot16 rightIntersectAf = FloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * rightSlope); + Q16Dot16 leftIntersectAf = FloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topLeftSlope); + Q16Dot16 rightIntersectAf = FloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topRightSlope); Q16Dot16 leftIntersectBf = 0; Q16Dot16 rightIntersectBf = 0; if (iLeftFP < iTopFP) - leftIntersectBf = FloatToQ16Dot16(left.x() + (int(topBound) - left.y()) * rightSlope); + leftIntersectBf = FloatToQ16Dot16(left.x() + (int(topBound) - left.y()) * bottomLeftSlope); if (iRightFP < iTopFP) - rightIntersectBf = FloatToQ16Dot16(right.x() + (int(topBound) - right.y()) * leftSlope); + rightIntersectBf = FloatToQ16Dot16(right.x() + (int(topBound) - right.y()) * bottomRightSlope); Q16Dot16 rowTop, rowBottomLeft, rowBottomRight, rowTopLeft, rowTopRight, rowBottom; Q16Dot16 topLeftIntersectAf, topLeftIntersectBf, topRightIntersectAf, topRightIntersectBf; @@ -960,9 +978,9 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, rowTop = qMax(iTopFP, yTopFP); topLeftIntersectAf = leftIntersectAf + - Q16Dot16Multiply(leftSlopeFP, rowTop - iTopFP); + Q16Dot16Multiply(topLeftSlopeFP, rowTop - iTopFP); topRightIntersectAf = rightIntersectAf + - Q16Dot16Multiply(rightSlopeFP, rowTop - iTopFP); + Q16Dot16Multiply(topRightSlopeFP, rowTop - iTopFP); Q16Dot16 yFP = iTopFP; while (yFP <= iBottomFP) { @@ -974,30 +992,30 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, if (yFP == iLeftFP) { const int y = Q16Dot16ToInt(yFP); - leftIntersectBf = FloatToQ16Dot16(left.x() + (y - left.y()) * rightSlope); - topLeftIntersectBf = leftIntersectBf + Q16Dot16Multiply(rightSlopeFP, rowTopLeft - yFP); - bottomLeftIntersectAf = leftIntersectAf + Q16Dot16Multiply(leftSlopeFP, rowBottomLeft - yFP); + leftIntersectBf = FloatToQ16Dot16(left.x() + (y - left.y()) * bottomLeftSlope); + topLeftIntersectBf = leftIntersectBf + Q16Dot16Multiply(bottomLeftSlopeFP, rowTopLeft - yFP); + bottomLeftIntersectAf = leftIntersectAf + Q16Dot16Multiply(topLeftSlopeFP, rowBottomLeft - yFP); } else { topLeftIntersectBf = leftIntersectBf; - bottomLeftIntersectAf = leftIntersectAf + leftSlopeFP; + bottomLeftIntersectAf = leftIntersectAf + topLeftSlopeFP; } if (yFP == iRightFP) { const int y = Q16Dot16ToInt(yFP); - rightIntersectBf = FloatToQ16Dot16(right.x() + (y - right.y()) * leftSlope); - topRightIntersectBf = rightIntersectBf + Q16Dot16Multiply(leftSlopeFP, rowTopRight - yFP); - bottomRightIntersectAf = rightIntersectAf + Q16Dot16Multiply(rightSlopeFP, rowBottomRight - yFP); + rightIntersectBf = FloatToQ16Dot16(right.x() + (y - right.y()) * bottomRightSlope); + topRightIntersectBf = rightIntersectBf + Q16Dot16Multiply(bottomRightSlopeFP, rowTopRight - yFP); + bottomRightIntersectAf = rightIntersectAf + Q16Dot16Multiply(topRightSlopeFP, rowBottomRight - yFP); } else { topRightIntersectBf = rightIntersectBf; - bottomRightIntersectAf = rightIntersectAf + rightSlopeFP; + bottomRightIntersectAf = rightIntersectAf + topRightSlopeFP; } if (yFP == iBottomFP) { - bottomLeftIntersectBf = leftIntersectBf + Q16Dot16Multiply(rightSlopeFP, rowBottom - yFP); - bottomRightIntersectBf = rightIntersectBf + Q16Dot16Multiply(leftSlopeFP, rowBottom - yFP); + bottomLeftIntersectBf = leftIntersectBf + Q16Dot16Multiply(bottomLeftSlopeFP, rowBottom - yFP); + bottomRightIntersectBf = rightIntersectBf + Q16Dot16Multiply(bottomRightSlopeFP, rowBottom - yFP); } else { - bottomLeftIntersectBf = leftIntersectBf + rightSlopeFP; - bottomRightIntersectBf = rightIntersectBf + leftSlopeFP; + bottomLeftIntersectBf = leftIntersectBf + bottomLeftSlopeFP; + bottomRightIntersectBf = rightIntersectBf + bottomRightSlopeFP; } if (yFP < iLeftFP) { @@ -1042,21 +1060,21 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, if (yFP <= iLeftFP) excluded += intersectPixelFP(x, rowTop, rowBottomLeft, bottomLeftIntersectAf, topLeftIntersectAf, - leftSlopeFP, -rightSlopeFP); + topLeftSlopeFP, invTopLeftSlopeFP); if (yFP >= iLeftFP) excluded += intersectPixelFP(x, rowTopLeft, rowBottom, topLeftIntersectBf, bottomLeftIntersectBf, - rightSlopeFP, -leftSlopeFP); + bottomLeftSlopeFP, invBottomLeftSlopeFP); if (x >= rightMin) { if (yFP <= iRightFP) excluded += (rowBottomRight - rowTop) - intersectPixelFP(x, rowTop, rowBottomRight, topRightIntersectAf, bottomRightIntersectAf, - rightSlopeFP, -leftSlopeFP); + topRightSlopeFP, invTopRightSlopeFP); if (yFP >= iRightFP) excluded += (rowBottom - rowTopRight) - intersectPixelFP(x, rowTopRight, rowBottom, bottomRightIntersectBf, topRightIntersectBf, - leftSlopeFP, -rightSlopeFP); + bottomRightSlopeFP, invBottomRightSlopeFP); } Q16Dot16 coverage = rowHeight - excluded; @@ -1074,11 +1092,11 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, if (yFP <= iRightFP) excluded += (rowBottomRight - rowTop) - intersectPixelFP(x, rowTop, rowBottomRight, topRightIntersectAf, bottomRightIntersectAf, - rightSlopeFP, -leftSlopeFP); + topRightSlopeFP, invTopRightSlopeFP); if (yFP >= iRightFP) excluded += (rowBottom - rowTopRight) - intersectPixelFP(x, rowTopRight, rowBottom, bottomRightIntersectBf, topRightIntersectBf, - leftSlopeFP, -rightSlopeFP); + bottomRightSlopeFP, invBottomRightSlopeFP); Q16Dot16 coverage = rowHeight - excluded; buffer.addSpan(x, 1, Q16Dot16ToInt(yFP), @@ -1086,10 +1104,10 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, ++x; } - leftIntersectAf += leftSlopeFP; - leftIntersectBf += rightSlopeFP; - rightIntersectAf += rightSlopeFP; - rightIntersectBf += leftSlopeFP; + leftIntersectAf += topLeftSlopeFP; + leftIntersectBf += bottomLeftSlopeFP; + rightIntersectAf += topRightSlopeFP; + rightIntersectBf += bottomRightSlopeFP; topLeftIntersectAf = leftIntersectAf; topRightIntersectAf = rightIntersectAf; @@ -1103,10 +1121,10 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, int iBottom = bottom.y() < 0.5f? -1 : int(bottom.y() - 0.5f); int iMiddle = qMin(iLeft, iRight); - Q16Dot16 leftIntersectAf = FloatToQ16Dot16(top.x() + 0.5f + (iTop + 0.5f - top.y()) * leftSlope); - Q16Dot16 leftIntersectBf = FloatToQ16Dot16(left.x() + 0.5f + (iLeft + 1.5f - left.y()) * rightSlope); - Q16Dot16 rightIntersectAf = FloatToQ16Dot16(top.x() - 0.5f + (iTop + 0.5f - top.y()) * rightSlope); - Q16Dot16 rightIntersectBf = FloatToQ16Dot16(right.x() - 0.5f + (iRight + 1.5f - right.y()) * leftSlope); + Q16Dot16 leftIntersectAf = FloatToQ16Dot16(top.x() + 0.5f + (iTop + 0.5f - top.y()) * topLeftSlope); + Q16Dot16 leftIntersectBf = FloatToQ16Dot16(left.x() + 0.5f + (iLeft + 1.5f - left.y()) * bottomLeftSlope); + Q16Dot16 rightIntersectAf = FloatToQ16Dot16(top.x() - 0.5f + (iTop + 0.5f - top.y()) * topRightSlope); + Q16Dot16 rightIntersectBf = FloatToQ16Dot16(right.x() - 0.5f + (iRight + 1.5f - right.y()) * bottomRightSlope); int ny; int y = iTop; @@ -1128,10 +1146,10 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, ri += rs; \ } - DO_SEGMENT(iMiddle, leftIntersectAf, rightIntersectAf, leftSlopeFP, rightSlopeFP) - DO_SEGMENT(iRight, leftIntersectBf, rightIntersectAf, rightSlopeFP, rightSlopeFP) - DO_SEGMENT(iLeft, leftIntersectAf, rightIntersectBf, leftSlopeFP, leftSlopeFP) - DO_SEGMENT(iBottom, leftIntersectBf, rightIntersectBf, rightSlopeFP, leftSlopeFP) + DO_SEGMENT(iMiddle, leftIntersectAf, rightIntersectAf, topLeftSlopeFP, topRightSlopeFP) + DO_SEGMENT(iRight, leftIntersectBf, rightIntersectAf, bottomLeftSlopeFP, topRightSlopeFP) + DO_SEGMENT(iLeft, leftIntersectAf, rightIntersectBf, topLeftSlopeFP, bottomRightSlopeFP); + DO_SEGMENT(iBottom, leftIntersectBf, rightIntersectBf, bottomLeftSlopeFP, bottomRightSlopeFP); #undef DO_SEGMENT } } @@ -1183,12 +1201,6 @@ void QRasterizer::rasterize(const QT_FT_Outline *outline, Qt::FillRule fillRule) d->scanConverter.end(); } -static inline QT_FT_Vector PointToVector(const QPointF &p) -{ - QT_FT_Vector result = { QT_FT_Pos(p.x() * 64), QT_FT_Pos(p.y() * 64) }; - return result; -} - void QRasterizer::rasterize(const QPainterPath &path, Qt::FillRule fillRule) { if (path.isEmpty()) |