Allow painting above INT16_MAX on 64-bit architectures
The logic in qgrayraster was ready for it except for an intermediate format. qrasterizer.cpp and qcosmeticstroker.cpp uses a dot-16 fixed point format, and had to be changed to handle higher coordinates on 64-bit architectures. Fixes: QTBUG-84428 Change-Id: I85ab7a04e38bd0dbcefa9f16c16ccc84785a33cf Reviewed-by: Lars Knoll <lars.knoll@qt.io>bb10
parent
ccc205bf38
commit
04413b9dd8
|
|
@ -58,6 +58,12 @@ inline QString capString(int caps)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if Q_PROCESSOR_WORDSIZE == 8
|
||||
typedef qint64 FDot16;
|
||||
#else
|
||||
typedef int FDot16;
|
||||
#endif
|
||||
|
||||
#define toF26Dot6(x) ((int)((x)*64.))
|
||||
|
||||
static inline uint sourceOver(uint d, uint color)
|
||||
|
|
@ -65,11 +71,15 @@ static inline uint sourceOver(uint d, uint color)
|
|||
return color + BYTE_MUL(d, qAlpha(~color));
|
||||
}
|
||||
|
||||
inline static int F16Dot16FixedDiv(int x, int y)
|
||||
inline static FDot16 FDot16FixedDiv(int x, int y)
|
||||
{
|
||||
#if Q_PROCESSOR_WORDSIZE == 8
|
||||
return FDot16(x) * (1<<16) / y;
|
||||
#else
|
||||
if (qAbs(x) > 0x7fff)
|
||||
return qlonglong(x) * (1<<16) / y;
|
||||
return x * (1<<16) / y;
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef void (*DrawPixel)(QCosmeticStroker *stroker, int x, int y, int coverage);
|
||||
|
|
@ -157,7 +167,7 @@ inline void drawPixel(QCosmeticStroker *stroker, int x, int y, int coverage)
|
|||
}
|
||||
}
|
||||
|
||||
stroker->spans[stroker->current_span].x = ushort(x);
|
||||
stroker->spans[stroker->current_span].x = x;
|
||||
stroker->spans[stroker->current_span].len = 1;
|
||||
stroker->spans[stroker->current_span].y = y;
|
||||
stroker->spans[stroker->current_span].coverage = coverage*stroker->opacity >> 8;
|
||||
|
|
@ -441,8 +451,8 @@ void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal
|
|||
qSwap(y1, y2);
|
||||
qSwap(x1, x2);
|
||||
}
|
||||
int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
|
||||
int x = x1 * (1<<10);
|
||||
FDot16 xinc = FDot16FixedDiv(x2 - x1, y2 - y1);
|
||||
FDot16 x = FDot16(x1) * (1<<10);
|
||||
|
||||
int y = (y1 + 32) >> 6;
|
||||
int ys = (y2 + 32) >> 6;
|
||||
|
|
@ -473,8 +483,8 @@ void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal
|
|||
qSwap(x1, x2);
|
||||
qSwap(y1, y2);
|
||||
}
|
||||
int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
|
||||
int y = y1 * (1 << 10);
|
||||
FDot16 yinc = FDot16FixedDiv(y2 - y1, x2 - x1);
|
||||
FDot16 y = FDot16(y1) * (1 << 10);
|
||||
|
||||
int x = (x1 + 32) >> 6;
|
||||
int xs = (x2 + 32) >> 6;
|
||||
|
|
@ -715,7 +725,7 @@ static inline int swapCaps(int caps)
|
|||
}
|
||||
|
||||
// adjust line by half a pixel
|
||||
static inline void capAdjust(int caps, int &x1, int &x2, int &y, int yinc)
|
||||
static inline void capAdjust(int caps, int &x1, int &x2, FDot16 &y, FDot16 yinc)
|
||||
{
|
||||
if (caps & QCosmeticStroker::CapBegin) {
|
||||
x1 -= 32;
|
||||
|
|
@ -763,8 +773,8 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
|
|||
caps = swapCaps(caps);
|
||||
dir = QCosmeticStroker::BottomToTop;
|
||||
}
|
||||
int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
|
||||
int x = x1 * (1<<10);
|
||||
FDot16 xinc = FDot16FixedDiv(x2 - x1, y2 - y1);
|
||||
FDot16 x = FDot16(x1) * (1<<10);
|
||||
|
||||
if ((stroker->lastDir ^ QCosmeticStroker::VerticalMask) == dir)
|
||||
caps |= swapped ? QCosmeticStroker::CapEnd : QCosmeticStroker::CapBegin;
|
||||
|
|
@ -853,8 +863,8 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
|
|||
caps = swapCaps(caps);
|
||||
dir = QCosmeticStroker::RightToLeft;
|
||||
}
|
||||
int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
|
||||
int y = y1 * (1<<10);
|
||||
FDot16 yinc = FDot16FixedDiv(y2 - y1, x2 - x1);
|
||||
FDot16 y = FDot16(y1) * (1<<10);
|
||||
|
||||
if ((stroker->lastDir ^ QCosmeticStroker::HorizontalMask) == dir)
|
||||
caps |= swapped ? QCosmeticStroker::CapEnd : QCosmeticStroker::CapBegin;
|
||||
|
|
@ -950,7 +960,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
|
|||
if (qAbs(dx) < qAbs(dy)) {
|
||||
// vertical
|
||||
|
||||
int xinc = F16Dot16FixedDiv(dx, dy);
|
||||
FDot16 xinc = FDot16FixedDiv(dx, dy);
|
||||
|
||||
bool swapped = false;
|
||||
if (y1 > y2) {
|
||||
|
|
@ -960,7 +970,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
|
|||
caps = swapCaps(caps);
|
||||
}
|
||||
|
||||
int x = (x1 - 32) * (1<<10);
|
||||
FDot16 x = FDot16(x1 - 32) * (1<<10);
|
||||
x -= ( ((y1 & 63) - 32) * xinc ) >> 6;
|
||||
|
||||
capAdjust(caps, y1, y2, x, xinc);
|
||||
|
|
@ -1013,7 +1023,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
|
|||
if (!dx)
|
||||
return true;
|
||||
|
||||
int yinc = F16Dot16FixedDiv(dy, dx);
|
||||
FDot16 yinc = FDot16FixedDiv(dy, dx);
|
||||
|
||||
bool swapped = false;
|
||||
if (x1 > x2) {
|
||||
|
|
@ -1023,7 +1033,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
|
|||
caps = swapCaps(caps);
|
||||
}
|
||||
|
||||
int y = (y1 - 32) * (1<<10);
|
||||
FDot16 y = FDot16(y1 - 32) * (1<<10);
|
||||
y -= ( ((x1 & 63) - 32) * yinc ) >> 6;
|
||||
|
||||
capAdjust(caps, x1, x2, y, yinc);
|
||||
|
|
|
|||
|
|
@ -1101,7 +1101,7 @@ QT_FT_END_STMNT
|
|||
L = QT_FT_HYPOT( dx_, dy_ );
|
||||
|
||||
/* Avoid possible arithmetic overflow below by splitting. */
|
||||
if ( L > 32767 )
|
||||
if ( L >= (1 << 23) )
|
||||
goto Split;
|
||||
|
||||
/* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */
|
||||
|
|
@ -1251,13 +1251,13 @@ QT_FT_END_STMNT
|
|||
y += (TCoord)ras.min_ey;
|
||||
x += (TCoord)ras.min_ex;
|
||||
|
||||
/* QT_FT_Span.x is a 16-bit short, so limit our coordinates appropriately */
|
||||
if ( x >= 32767 )
|
||||
x = 32767;
|
||||
/* QT_FT_Span.x is an int, so limit our coordinates appropriately */
|
||||
if ( x >= (1 << 23) )
|
||||
x = (1 << 23) - 1;
|
||||
|
||||
/* QT_FT_Span.y is a 16-bit short, so limit our coordinates appropriately */
|
||||
if ( y >= 32767 )
|
||||
y = 32767;
|
||||
/* QT_FT_Span.y is an int, so limit our coordinates appropriately */
|
||||
if ( y >= (1 << 23) )
|
||||
y = (1 << 23) - 1;
|
||||
|
||||
if ( coverage )
|
||||
{
|
||||
|
|
@ -1271,10 +1271,10 @@ QT_FT_END_STMNT
|
|||
span = ras.gray_spans + count - 1;
|
||||
if ( count > 0 &&
|
||||
span->y == y &&
|
||||
(int)span->x + span->len == (int)x &&
|
||||
span->x + span->len == x &&
|
||||
span->coverage == coverage )
|
||||
{
|
||||
span->len = (unsigned short)( span->len + acount );
|
||||
span->len = span->len + acount;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1317,9 +1317,9 @@ QT_FT_END_STMNT
|
|||
span++;
|
||||
|
||||
/* add a gray span to the current list */
|
||||
span->x = (short)x;
|
||||
span->len = (unsigned short)acount;
|
||||
span->y = (short)y;
|
||||
span->x = x;
|
||||
span->len = acount;
|
||||
span->y = y;
|
||||
span->coverage = (unsigned char)coverage;
|
||||
|
||||
ras.num_gray_spans++;
|
||||
|
|
@ -1895,10 +1895,10 @@ QT_FT_END_STMNT
|
|||
}
|
||||
else
|
||||
{
|
||||
ras.clip_box.xMin = -32768L;
|
||||
ras.clip_box.yMin = -32768L;
|
||||
ras.clip_box.xMax = 32767L;
|
||||
ras.clip_box.yMax = 32767L;
|
||||
ras.clip_box.xMin = -(1 << 23);
|
||||
ras.clip_box.yMin = -(1 << 23);
|
||||
ras.clip_box.xMax = (1 << 23) - 1;
|
||||
ras.clip_box.yMax = (1 << 23) - 1;
|
||||
}
|
||||
|
||||
gray_init_cells( worker, raster->buffer, raster->buffer_size );
|
||||
|
|
|
|||
|
|
@ -66,10 +66,13 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
// This limitations comes from qgrayraster.c. Any higher and
|
||||
// rasterization of shapes will produce incorrect results.
|
||||
const int QT_RASTER_COORD_LIMIT = 32767;
|
||||
|
||||
// These limitations comes from qrasterizer.cpp, qcosmeticstroker.cpp, and qgrayraster.c.
|
||||
// Any higher and rasterization of shapes will produce incorrect results.
|
||||
#if Q_PROCESSOR_WORDSIZE == 8
|
||||
constexpr int QT_RASTER_COORD_LIMIT = ((1<<23) - 1); // F24dot8 in qgrayraster.c
|
||||
#else
|
||||
constexpr int QT_RASTER_COORD_LIMIT = ((1<<15) - 1); // F16dot16 in qrasterizer.cpp and qcosmeticstroker.cpp
|
||||
#endif
|
||||
//#define QT_DEBUG_CONVERT
|
||||
|
||||
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
|
||||
|
|
|
|||
|
|
@ -4142,10 +4142,10 @@ static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userDa
|
|||
static int qt_intersect_spans(QT_FT_Span *&spans, int numSpans,
|
||||
const QRect &clip)
|
||||
{
|
||||
const short minx = clip.left();
|
||||
const short miny = clip.top();
|
||||
const short maxx = clip.right();
|
||||
const short maxy = clip.bottom();
|
||||
const int minx = clip.left();
|
||||
const int miny = clip.top();
|
||||
const int maxx = clip.right();
|
||||
const int maxy = clip.bottom();
|
||||
|
||||
QT_FT_Span *end = spans + numSpans;
|
||||
while (spans < end) {
|
||||
|
|
@ -4167,7 +4167,7 @@ static int qt_intersect_spans(QT_FT_Span *&spans, int numSpans,
|
|||
s->len = qMin(s->len - (minx - s->x), maxx - minx + 1);
|
||||
s->x = minx;
|
||||
} else {
|
||||
s->len = qMin(s->len, ushort(maxx - s->x + 1));
|
||||
s->len = qMin(s->len, (maxx - s->x + 1));
|
||||
}
|
||||
++s;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -865,10 +865,10 @@ QT_FT_BEGIN_HEADER
|
|||
/* */
|
||||
typedef struct QT_FT_Span_
|
||||
{
|
||||
short x;
|
||||
unsigned short len;
|
||||
short y;
|
||||
unsigned char coverage;
|
||||
int x;
|
||||
int len;
|
||||
int y;
|
||||
unsigned char coverage;
|
||||
} QT_FT_Span;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -52,15 +52,20 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
typedef int Q16Dot16;
|
||||
#define Q16Dot16ToFloat(i) ((i)/65536.)
|
||||
#define FloatToQ16Dot16(i) (int)((i) * 65536.)
|
||||
#define IntToQ16Dot16(i) ((i) * (1 << 16))
|
||||
#define Q16Dot16ToInt(i) ((i) >> 16)
|
||||
#define Q16Dot16Factor 65536
|
||||
#if Q_PROCESSOR_WORDSIZE == 8
|
||||
typedef qint64 QScFixed;
|
||||
#else
|
||||
typedef int QScFixed;
|
||||
#endif
|
||||
#define QScFixedToFloat(i) ((i) * (1./65536.))
|
||||
#define FloatToQScFixed(i) (QScFixed)((i) * 65536.)
|
||||
#define IntToQScFixed(i) ((QScFixed)(i) * (1 << 16))
|
||||
#define QScFixedToInt(i) ((i) >> 16)
|
||||
#define QScFixedFactor 65536
|
||||
#define FTPosToQScFixed(i) ((QScFixed)(i) * (1 << 10))
|
||||
|
||||
#define Q16Dot16Multiply(x, y) (int)((qlonglong(x) * qlonglong(y)) >> 16)
|
||||
#define Q16Dot16FastMultiply(x, y) (((x) * (y)) >> 16)
|
||||
#define QScFixedMultiply(x, y) (QScFixed)((qlonglong(x) * qlonglong(y)) >> 16)
|
||||
#define QScFixedFastMultiply(x, y) (((x) * (y)) >> 16)
|
||||
|
||||
#define SPAN_BUFFER_SIZE 256
|
||||
|
||||
|
|
@ -88,11 +93,12 @@ public:
|
|||
flushSpans();
|
||||
}
|
||||
|
||||
void addSpan(int x, unsigned int len, int y, unsigned char coverage)
|
||||
void addSpan(int x, int len, int y, int coverage)
|
||||
{
|
||||
if (!coverage || !len)
|
||||
return;
|
||||
|
||||
Q_ASSERT(coverage >= 0 && coverage <= 255);
|
||||
Q_ASSERT(y >= m_clipRect.top());
|
||||
Q_ASSERT(y <= m_clipRect.bottom());
|
||||
Q_ASSERT(x >= m_clipRect.left());
|
||||
|
|
@ -140,8 +146,8 @@ public:
|
|||
|
||||
struct Line
|
||||
{
|
||||
Q16Dot16 x;
|
||||
Q16Dot16 delta;
|
||||
QScFixed x;
|
||||
QScFixed delta;
|
||||
|
||||
int top, bottom;
|
||||
|
||||
|
|
@ -157,7 +163,7 @@ private:
|
|||
int left, right;
|
||||
};
|
||||
|
||||
inline bool clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot16 slopeFP, Q16Dot16 edgeFP, int winding);
|
||||
inline bool clip(QScFixed &xFP, int &iTop, int &iBottom, QScFixed slopeFP, QScFixed edgeFP, int winding);
|
||||
inline void mergeIntersection(Intersection *head, const Intersection &isect);
|
||||
|
||||
void prepareChunk();
|
||||
|
|
@ -175,8 +181,8 @@ private:
|
|||
int m_top;
|
||||
int m_bottom;
|
||||
|
||||
Q16Dot16 m_leftFP;
|
||||
Q16Dot16 m_rightFP;
|
||||
QScFixed m_leftFP;
|
||||
QScFixed m_rightFP;
|
||||
|
||||
int m_fillRuleMask;
|
||||
bool m_legacyRounding;
|
||||
|
|
@ -228,8 +234,8 @@ void QScanConverter::begin(int top, int bottom, int left, int right,
|
|||
{
|
||||
m_top = top;
|
||||
m_bottom = bottom;
|
||||
m_leftFP = IntToQ16Dot16(left);
|
||||
m_rightFP = IntToQ16Dot16(right + 1);
|
||||
m_leftFP = IntToQScFixed(left);
|
||||
m_rightFP = IntToQScFixed(right + 1);
|
||||
|
||||
m_lines.reset();
|
||||
|
||||
|
|
@ -350,7 +356,7 @@ void QScanConverter::scanConvert()
|
|||
for (int i = 0; i < numActive; ++i) {
|
||||
QScanConverter::Line *node = m_active.at(i);
|
||||
|
||||
const int current = Q16Dot16ToInt(node->x);
|
||||
const int current = QScFixedToInt(node->x);
|
||||
if (winding & m_fillRuleMask)
|
||||
m_spanBuffer->addSpan(x, current - x, y, 0xff);
|
||||
|
||||
|
|
@ -414,12 +420,12 @@ void QScanConverter::end()
|
|||
|
||||
if (line.delta) {
|
||||
for (; it != end; ++it) {
|
||||
isect.x = Q16Dot16ToInt(line.x);
|
||||
isect.x = QScFixedToInt(line.x);
|
||||
line.x += line.delta;
|
||||
mergeIntersection(it, isect);
|
||||
}
|
||||
} else {
|
||||
isect.x = Q16Dot16ToInt(line.x);
|
||||
isect.x = QScFixedToInt(line.x);
|
||||
for (; it != end; ++it)
|
||||
mergeIntersection(it, isect);
|
||||
}
|
||||
|
|
@ -516,7 +522,7 @@ void QScanConverter::mergeCurve(const QT_FT_Vector &pa, const QT_FT_Vector &pb,
|
|||
}
|
||||
}
|
||||
|
||||
inline bool QScanConverter::clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot16 slopeFP, Q16Dot16 edgeFP, int winding)
|
||||
inline bool QScanConverter::clip(QScFixed &xFP, int &iTop, int &iBottom, QScFixed slopeFP, QScFixed edgeFP, int winding)
|
||||
{
|
||||
bool right = edgeFP == m_rightFP;
|
||||
|
||||
|
|
@ -530,7 +536,7 @@ inline bool QScanConverter::clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot1
|
|||
}
|
||||
}
|
||||
|
||||
Q16Dot16 lastFP = xFP + slopeFP * (iBottom - iTop);
|
||||
QScFixed lastFP = xFP + slopeFP * (iBottom - iTop);
|
||||
|
||||
if (lastFP == edgeFP) {
|
||||
if ((slopeFP < 0) ^ right)
|
||||
|
|
@ -544,11 +550,11 @@ inline bool QScanConverter::clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot1
|
|||
|
||||
// does line cross edge?
|
||||
if ((lastFP < edgeFP) ^ (xFP < edgeFP)) {
|
||||
Q16Dot16 deltaY = Q16Dot16((edgeFP - xFP) / Q16Dot16ToFloat(slopeFP));
|
||||
QScFixed deltaY = QScFixed((edgeFP - xFP) / QScFixedToFloat(slopeFP));
|
||||
|
||||
if ((xFP < edgeFP) ^ right) {
|
||||
// top segment needs to be clipped
|
||||
int iHeight = Q16Dot16ToInt(deltaY + 1);
|
||||
int iHeight = QScFixedToInt(deltaY + 1);
|
||||
int iMiddle = iTop + iHeight;
|
||||
|
||||
Line line = { edgeFP, 0, iTop, iMiddle, winding };
|
||||
|
|
@ -561,7 +567,7 @@ inline bool QScanConverter::clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot1
|
|||
return true;
|
||||
} else {
|
||||
// bottom segment needs to be clipped
|
||||
int iHeight = Q16Dot16ToInt(deltaY);
|
||||
int iHeight = QScFixedToInt(deltaY);
|
||||
int iMiddle = iTop + iHeight;
|
||||
|
||||
if (iMiddle != iBottom) {
|
||||
|
|
@ -603,7 +609,7 @@ void QScanConverter::mergeLine(QT_FT_Vector a, QT_FT_Vector b)
|
|||
int iBottom = qMin(m_bottom, int((b.y - 32 - rounding) >> 6));
|
||||
|
||||
if (iTop <= iBottom) {
|
||||
Q16Dot16 aFP = Q16Dot16Factor/2 + (a.x * (1 << 10)) - rounding;
|
||||
QScFixed aFP = QScFixedFactor/2 + FTPosToQScFixed(a.x - rounding);
|
||||
|
||||
if (b.x == a.x) {
|
||||
Line line = { qBound(m_leftFP, aFP, m_rightFP), 0, iTop, iBottom, winding };
|
||||
|
|
@ -611,11 +617,11 @@ void QScanConverter::mergeLine(QT_FT_Vector a, QT_FT_Vector b)
|
|||
} else {
|
||||
const qreal slope = (b.x - a.x) / qreal(b.y - a.y);
|
||||
|
||||
const Q16Dot16 slopeFP = FloatToQ16Dot16(slope);
|
||||
const QScFixed slopeFP = FloatToQScFixed(slope);
|
||||
|
||||
Q16Dot16 xFP = aFP + Q16Dot16Multiply(slopeFP,
|
||||
IntToQ16Dot16(iTop)
|
||||
+ Q16Dot16Factor/2 - (a.y * (1 << 10)));
|
||||
QScFixed xFP = aFP + QScFixedMultiply(slopeFP,
|
||||
IntToQScFixed(iTop)
|
||||
+ QScFixedFactor/2 - FTPosToQScFixed(a.y));
|
||||
|
||||
if (clip(xFP, iTop, iBottom, slopeFP, m_leftFP, winding))
|
||||
return;
|
||||
|
|
@ -663,37 +669,37 @@ void QRasterizer::setLegacyRoundingEnabled(bool legacyRoundingEnabled)
|
|||
d->legacyRounding = legacyRoundingEnabled;
|
||||
}
|
||||
|
||||
static Q16Dot16 intersectPixelFP(int x, Q16Dot16 top, Q16Dot16 bottom, Q16Dot16 leftIntersectX, Q16Dot16 rightIntersectX, Q16Dot16 slope, Q16Dot16 invSlope)
|
||||
static QScFixed intersectPixelFP(int x, QScFixed top, QScFixed bottom, QScFixed leftIntersectX, QScFixed rightIntersectX, QScFixed slope, QScFixed invSlope)
|
||||
{
|
||||
Q16Dot16 leftX = IntToQ16Dot16(x);
|
||||
Q16Dot16 rightX = IntToQ16Dot16(x) + Q16Dot16Factor;
|
||||
QScFixed leftX = IntToQScFixed(x);
|
||||
QScFixed rightX = IntToQScFixed(x) + QScFixedFactor;
|
||||
|
||||
Q16Dot16 leftIntersectY, rightIntersectY;
|
||||
QScFixed leftIntersectY, rightIntersectY;
|
||||
if (slope > 0) {
|
||||
leftIntersectY = top + Q16Dot16Multiply(leftX - leftIntersectX, invSlope);
|
||||
leftIntersectY = top + QScFixedMultiply(leftX - leftIntersectX, invSlope);
|
||||
rightIntersectY = leftIntersectY + invSlope;
|
||||
} else {
|
||||
leftIntersectY = top + Q16Dot16Multiply(leftX - rightIntersectX, invSlope);
|
||||
leftIntersectY = top + QScFixedMultiply(leftX - rightIntersectX, invSlope);
|
||||
rightIntersectY = leftIntersectY + invSlope;
|
||||
}
|
||||
|
||||
if (leftIntersectX >= leftX && rightIntersectX <= rightX) {
|
||||
return Q16Dot16Multiply(bottom - top, leftIntersectX - leftX + ((rightIntersectX - leftIntersectX) >> 1));
|
||||
return QScFixedMultiply(bottom - top, leftIntersectX - leftX + ((rightIntersectX - leftIntersectX) >> 1));
|
||||
} else if (leftIntersectX >= rightX) {
|
||||
return bottom - top;
|
||||
} else if (leftIntersectX >= leftX) {
|
||||
if (slope > 0) {
|
||||
return (bottom - top) - Q16Dot16FastMultiply((rightX - leftIntersectX) >> 1, rightIntersectY - top);
|
||||
return (bottom - top) - QScFixedFastMultiply((rightX - leftIntersectX) >> 1, rightIntersectY - top);
|
||||
} else {
|
||||
return (bottom - top) - Q16Dot16FastMultiply((rightX - leftIntersectX) >> 1, bottom - rightIntersectY);
|
||||
return (bottom - top) - QScFixedFastMultiply((rightX - leftIntersectX) >> 1, bottom - rightIntersectY);
|
||||
}
|
||||
} else if (rightIntersectX <= leftX) {
|
||||
return 0;
|
||||
} else if (rightIntersectX <= rightX) {
|
||||
if (slope > 0) {
|
||||
return Q16Dot16FastMultiply((rightIntersectX - leftX) >> 1, bottom - leftIntersectY);
|
||||
return QScFixedFastMultiply((rightIntersectX - leftX) >> 1, bottom - leftIntersectY);
|
||||
} else {
|
||||
return Q16Dot16FastMultiply((rightIntersectX - leftX) >> 1, leftIntersectY - top);
|
||||
return QScFixedFastMultiply((rightIntersectX - leftX) >> 1, leftIntersectY - top);
|
||||
}
|
||||
} else {
|
||||
if (slope > 0) {
|
||||
|
|
@ -734,14 +740,14 @@ static inline qreal qSafeDivide(qreal x, qreal y)
|
|||
too small to fit into INT_MIN, so we need this slightly safer conversion
|
||||
when floating point exceptions are enabled
|
||||
*/
|
||||
static inline int qSafeFloatToQ16Dot16(qreal x)
|
||||
static inline QScFixed qSafeFloatToQScFixed(qreal x)
|
||||
{
|
||||
qreal tmp = x * 65536.;
|
||||
if (tmp > qreal(INT_MAX))
|
||||
return INT_MAX;
|
||||
else if (tmp < qreal(INT_MIN))
|
||||
return -INT_MAX;
|
||||
return int(tmp);
|
||||
qreal tmp = x * QScFixedFactor;
|
||||
if (tmp > qreal(std::numeric_limits<QScFixed>::max()))
|
||||
return std::numeric_limits<QScFixed>::max();
|
||||
else if (tmp < qreal(std::numeric_limits<QScFixed>::min()))
|
||||
return std::numeric_limits<QScFixed>::min();
|
||||
return QScFixed(tmp);
|
||||
}
|
||||
|
||||
void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, bool squareCap)
|
||||
|
|
@ -855,30 +861,33 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
|
|||
return;
|
||||
|
||||
if (d->antialiased) {
|
||||
const Q16Dot16 iLeft = int(left);
|
||||
const Q16Dot16 iRight = int(right);
|
||||
const Q16Dot16 leftWidth = IntToQ16Dot16(iLeft + 1)
|
||||
- qSafeFloatToQ16Dot16(left);
|
||||
const Q16Dot16 rightWidth = qSafeFloatToQ16Dot16(right)
|
||||
- IntToQ16Dot16(iRight);
|
||||
const int iLeft = int(left);
|
||||
const int iRight = int(right);
|
||||
const QScFixed leftWidth = IntToQScFixed(iLeft + 1)
|
||||
- qSafeFloatToQScFixed(left);
|
||||
const QScFixed rightWidth = qSafeFloatToQScFixed(right)
|
||||
- IntToQScFixed(iRight);
|
||||
|
||||
Q16Dot16 coverage[3];
|
||||
QScFixed coverage[3];
|
||||
int x[3];
|
||||
int len[3];
|
||||
|
||||
int n = 1;
|
||||
if (iLeft == iRight) {
|
||||
coverage[0] = (leftWidth + rightWidth) * 255;
|
||||
if (leftWidth == QScFixedFactor)
|
||||
coverage[0] = rightWidth * 255;
|
||||
else
|
||||
coverage[0] = (leftWidth + rightWidth) * 255;
|
||||
x[0] = iLeft;
|
||||
len[0] = 1;
|
||||
} else {
|
||||
coverage[0] = leftWidth * 255;
|
||||
x[0] = iLeft;
|
||||
len[0] = 1;
|
||||
if (leftWidth == Q16Dot16Factor) {
|
||||
if (leftWidth == QScFixedFactor) {
|
||||
len[0] = iRight - iLeft;
|
||||
} else if (iRight - iLeft > 1) {
|
||||
coverage[1] = IntToQ16Dot16(255);
|
||||
coverage[1] = IntToQScFixed(255);
|
||||
x[1] = iLeft + 1;
|
||||
len[1] = iRight - iLeft - 1;
|
||||
++n;
|
||||
|
|
@ -891,19 +900,19 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
|
|||
}
|
||||
}
|
||||
|
||||
const Q16Dot16 iTopFP = IntToQ16Dot16(int(pa.y()));
|
||||
const Q16Dot16 iBottomFP = IntToQ16Dot16(int(pb.y()));
|
||||
const Q16Dot16 yPa = qSafeFloatToQ16Dot16(pa.y());
|
||||
const Q16Dot16 yPb = qSafeFloatToQ16Dot16(pb.y());
|
||||
for (Q16Dot16 yFP = iTopFP; yFP <= iBottomFP; yFP += Q16Dot16Factor) {
|
||||
const Q16Dot16 rowHeight = qMin(yFP + Q16Dot16Factor, yPb)
|
||||
const QScFixed iTopFP = IntToQScFixed(int(pa.y()));
|
||||
const QScFixed iBottomFP = IntToQScFixed(int(pb.y()));
|
||||
const QScFixed yPa = qSafeFloatToQScFixed(pa.y());
|
||||
const QScFixed yPb = qSafeFloatToQScFixed(pb.y());
|
||||
for (QScFixed yFP = iTopFP; yFP <= iBottomFP; yFP += QScFixedFactor) {
|
||||
const QScFixed rowHeight = qMin(yFP + QScFixedFactor, yPb)
|
||||
- qMax(yFP, yPa);
|
||||
const int y = Q16Dot16ToInt(yFP);
|
||||
const int y = QScFixedToInt(yFP);
|
||||
if (y > d->clipRect.bottom())
|
||||
break;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
buffer.addSpan(x[i], len[i], y,
|
||||
Q16Dot16ToInt(Q16Dot16Multiply(rowHeight, coverage[i])));
|
||||
QScFixedToInt(QScFixedMultiply(rowHeight, coverage[i])));
|
||||
}
|
||||
}
|
||||
} else { // aliased
|
||||
|
|
@ -960,111 +969,111 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
|
|||
const qreal topRightSlope = qSafeDivide(topRightEdge.x(), topRightEdge.y());
|
||||
const qreal bottomRightSlope = qSafeDivide(bottomRightEdge.x(), bottomRightEdge.y());
|
||||
|
||||
const Q16Dot16 topLeftSlopeFP = qSafeFloatToQ16Dot16(topLeftSlope);
|
||||
const Q16Dot16 topRightSlopeFP = qSafeFloatToQ16Dot16(topRightSlope);
|
||||
const QScFixed topLeftSlopeFP = qSafeFloatToQScFixed(topLeftSlope);
|
||||
const QScFixed topRightSlopeFP = qSafeFloatToQScFixed(topRightSlope);
|
||||
|
||||
const Q16Dot16 bottomLeftSlopeFP = qSafeFloatToQ16Dot16(bottomLeftSlope);
|
||||
const Q16Dot16 bottomRightSlopeFP = qSafeFloatToQ16Dot16(bottomRightSlope);
|
||||
const QScFixed bottomLeftSlopeFP = qSafeFloatToQScFixed(bottomLeftSlope);
|
||||
const QScFixed bottomRightSlopeFP = qSafeFloatToQScFixed(bottomRightSlope);
|
||||
|
||||
const Q16Dot16 invTopLeftSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, topLeftSlope));
|
||||
const Q16Dot16 invTopRightSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, topRightSlope));
|
||||
const QScFixed invTopLeftSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, topLeftSlope));
|
||||
const QScFixed invTopRightSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, topRightSlope));
|
||||
|
||||
const Q16Dot16 invBottomLeftSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, bottomLeftSlope));
|
||||
const Q16Dot16 invBottomRightSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, bottomRightSlope));
|
||||
const QScFixed invBottomLeftSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, bottomLeftSlope));
|
||||
const QScFixed invBottomRightSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, bottomRightSlope));
|
||||
|
||||
if (d->antialiased) {
|
||||
const Q16Dot16 iTopFP = IntToQ16Dot16(int(topBound));
|
||||
const Q16Dot16 iLeftFP = IntToQ16Dot16(int(left.y()));
|
||||
const Q16Dot16 iRightFP = IntToQ16Dot16(int(right.y()));
|
||||
const Q16Dot16 iBottomFP = IntToQ16Dot16(int(bottomBound));
|
||||
const QScFixed iTopFP = IntToQScFixed(int(topBound));
|
||||
const QScFixed iLeftFP = IntToQScFixed(int(left.y()));
|
||||
const QScFixed iRightFP = IntToQScFixed(int(right.y()));
|
||||
const QScFixed iBottomFP = IntToQScFixed(int(bottomBound));
|
||||
|
||||
Q16Dot16 leftIntersectAf = qSafeFloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topLeftSlope);
|
||||
Q16Dot16 rightIntersectAf = qSafeFloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topRightSlope);
|
||||
Q16Dot16 leftIntersectBf = 0;
|
||||
Q16Dot16 rightIntersectBf = 0;
|
||||
QScFixed leftIntersectAf = qSafeFloatToQScFixed(top.x() + (int(topBound) - top.y()) * topLeftSlope);
|
||||
QScFixed rightIntersectAf = qSafeFloatToQScFixed(top.x() + (int(topBound) - top.y()) * topRightSlope);
|
||||
QScFixed leftIntersectBf = 0;
|
||||
QScFixed rightIntersectBf = 0;
|
||||
|
||||
if (iLeftFP < iTopFP)
|
||||
leftIntersectBf = qSafeFloatToQ16Dot16(left.x() + (int(topBound) - left.y()) * bottomLeftSlope);
|
||||
leftIntersectBf = qSafeFloatToQScFixed(left.x() + (int(topBound) - left.y()) * bottomLeftSlope);
|
||||
|
||||
if (iRightFP < iTopFP)
|
||||
rightIntersectBf = qSafeFloatToQ16Dot16(right.x() + (int(topBound) - right.y()) * bottomRightSlope);
|
||||
rightIntersectBf = qSafeFloatToQScFixed(right.x() + (int(topBound) - right.y()) * bottomRightSlope);
|
||||
|
||||
Q16Dot16 rowTop, rowBottomLeft, rowBottomRight, rowTopLeft, rowTopRight, rowBottom;
|
||||
Q16Dot16 topLeftIntersectAf, topLeftIntersectBf, topRightIntersectAf, topRightIntersectBf;
|
||||
Q16Dot16 bottomLeftIntersectAf, bottomLeftIntersectBf, bottomRightIntersectAf, bottomRightIntersectBf;
|
||||
QScFixed rowTop, rowBottomLeft, rowBottomRight, rowTopLeft, rowTopRight, rowBottom;
|
||||
QScFixed topLeftIntersectAf, topLeftIntersectBf, topRightIntersectAf, topRightIntersectBf;
|
||||
QScFixed bottomLeftIntersectAf, bottomLeftIntersectBf, bottomRightIntersectAf, bottomRightIntersectBf;
|
||||
|
||||
int leftMin, leftMax, rightMin, rightMax;
|
||||
|
||||
const Q16Dot16 yTopFP = qSafeFloatToQ16Dot16(top.y());
|
||||
const Q16Dot16 yLeftFP = qSafeFloatToQ16Dot16(left.y());
|
||||
const Q16Dot16 yRightFP = qSafeFloatToQ16Dot16(right.y());
|
||||
const Q16Dot16 yBottomFP = qSafeFloatToQ16Dot16(bottom.y());
|
||||
const QScFixed yTopFP = qSafeFloatToQScFixed(top.y());
|
||||
const QScFixed yLeftFP = qSafeFloatToQScFixed(left.y());
|
||||
const QScFixed yRightFP = qSafeFloatToQScFixed(right.y());
|
||||
const QScFixed yBottomFP = qSafeFloatToQScFixed(bottom.y());
|
||||
|
||||
rowTop = qMax(iTopFP, yTopFP);
|
||||
topLeftIntersectAf = leftIntersectAf +
|
||||
Q16Dot16Multiply(topLeftSlopeFP, rowTop - iTopFP);
|
||||
QScFixedMultiply(topLeftSlopeFP, rowTop - iTopFP);
|
||||
topRightIntersectAf = rightIntersectAf +
|
||||
Q16Dot16Multiply(topRightSlopeFP, rowTop - iTopFP);
|
||||
QScFixedMultiply(topRightSlopeFP, rowTop - iTopFP);
|
||||
|
||||
Q16Dot16 yFP = iTopFP;
|
||||
QScFixed yFP = iTopFP;
|
||||
while (yFP <= iBottomFP) {
|
||||
rowBottomLeft = qMin(yFP + Q16Dot16Factor, yLeftFP);
|
||||
rowBottomRight = qMin(yFP + Q16Dot16Factor, yRightFP);
|
||||
rowBottomLeft = qMin(yFP + QScFixedFactor, yLeftFP);
|
||||
rowBottomRight = qMin(yFP + QScFixedFactor, yRightFP);
|
||||
rowTopLeft = qMax(yFP, yLeftFP);
|
||||
rowTopRight = qMax(yFP, yRightFP);
|
||||
rowBottom = qMin(yFP + Q16Dot16Factor, yBottomFP);
|
||||
rowBottom = qMin(yFP + QScFixedFactor, yBottomFP);
|
||||
|
||||
if (yFP == iLeftFP) {
|
||||
const int y = Q16Dot16ToInt(yFP);
|
||||
leftIntersectBf = qSafeFloatToQ16Dot16(left.x() + (y - left.y()) * bottomLeftSlope);
|
||||
topLeftIntersectBf = leftIntersectBf + Q16Dot16Multiply(bottomLeftSlopeFP, rowTopLeft - yFP);
|
||||
bottomLeftIntersectAf = leftIntersectAf + Q16Dot16Multiply(topLeftSlopeFP, rowBottomLeft - yFP);
|
||||
const int y = QScFixedToInt(yFP);
|
||||
leftIntersectBf = qSafeFloatToQScFixed(left.x() + (y - left.y()) * bottomLeftSlope);
|
||||
topLeftIntersectBf = leftIntersectBf + QScFixedMultiply(bottomLeftSlopeFP, rowTopLeft - yFP);
|
||||
bottomLeftIntersectAf = leftIntersectAf + QScFixedMultiply(topLeftSlopeFP, rowBottomLeft - yFP);
|
||||
} else {
|
||||
topLeftIntersectBf = leftIntersectBf;
|
||||
bottomLeftIntersectAf = leftIntersectAf + topLeftSlopeFP;
|
||||
}
|
||||
|
||||
if (yFP == iRightFP) {
|
||||
const int y = Q16Dot16ToInt(yFP);
|
||||
rightIntersectBf = qSafeFloatToQ16Dot16(right.x() + (y - right.y()) * bottomRightSlope);
|
||||
topRightIntersectBf = rightIntersectBf + Q16Dot16Multiply(bottomRightSlopeFP, rowTopRight - yFP);
|
||||
bottomRightIntersectAf = rightIntersectAf + Q16Dot16Multiply(topRightSlopeFP, rowBottomRight - yFP);
|
||||
const int y = QScFixedToInt(yFP);
|
||||
rightIntersectBf = qSafeFloatToQScFixed(right.x() + (y - right.y()) * bottomRightSlope);
|
||||
topRightIntersectBf = rightIntersectBf + QScFixedMultiply(bottomRightSlopeFP, rowTopRight - yFP);
|
||||
bottomRightIntersectAf = rightIntersectAf + QScFixedMultiply(topRightSlopeFP, rowBottomRight - yFP);
|
||||
} else {
|
||||
topRightIntersectBf = rightIntersectBf;
|
||||
bottomRightIntersectAf = rightIntersectAf + topRightSlopeFP;
|
||||
}
|
||||
|
||||
if (yFP == iBottomFP) {
|
||||
bottomLeftIntersectBf = leftIntersectBf + Q16Dot16Multiply(bottomLeftSlopeFP, rowBottom - yFP);
|
||||
bottomRightIntersectBf = rightIntersectBf + Q16Dot16Multiply(bottomRightSlopeFP, rowBottom - yFP);
|
||||
bottomLeftIntersectBf = leftIntersectBf + QScFixedMultiply(bottomLeftSlopeFP, rowBottom - yFP);
|
||||
bottomRightIntersectBf = rightIntersectBf + QScFixedMultiply(bottomRightSlopeFP, rowBottom - yFP);
|
||||
} else {
|
||||
bottomLeftIntersectBf = leftIntersectBf + bottomLeftSlopeFP;
|
||||
bottomRightIntersectBf = rightIntersectBf + bottomRightSlopeFP;
|
||||
}
|
||||
|
||||
if (yFP < iLeftFP) {
|
||||
leftMin = Q16Dot16ToInt(bottomLeftIntersectAf);
|
||||
leftMax = Q16Dot16ToInt(topLeftIntersectAf);
|
||||
leftMin = QScFixedToInt(bottomLeftIntersectAf);
|
||||
leftMax = QScFixedToInt(topLeftIntersectAf);
|
||||
} else if (yFP == iLeftFP) {
|
||||
leftMin = Q16Dot16ToInt(qMax(bottomLeftIntersectAf, topLeftIntersectBf));
|
||||
leftMax = Q16Dot16ToInt(qMax(topLeftIntersectAf, bottomLeftIntersectBf));
|
||||
leftMin = QScFixedToInt(qMax(bottomLeftIntersectAf, topLeftIntersectBf));
|
||||
leftMax = QScFixedToInt(qMax(topLeftIntersectAf, bottomLeftIntersectBf));
|
||||
} else {
|
||||
leftMin = Q16Dot16ToInt(topLeftIntersectBf);
|
||||
leftMax = Q16Dot16ToInt(bottomLeftIntersectBf);
|
||||
leftMin = QScFixedToInt(topLeftIntersectBf);
|
||||
leftMax = QScFixedToInt(bottomLeftIntersectBf);
|
||||
}
|
||||
|
||||
leftMin = qBound(d->clipRect.left(), leftMin, d->clipRect.right());
|
||||
leftMax = qBound(d->clipRect.left(), leftMax, d->clipRect.right());
|
||||
|
||||
if (yFP < iRightFP) {
|
||||
rightMin = Q16Dot16ToInt(topRightIntersectAf);
|
||||
rightMax = Q16Dot16ToInt(bottomRightIntersectAf);
|
||||
rightMin = QScFixedToInt(topRightIntersectAf);
|
||||
rightMax = QScFixedToInt(bottomRightIntersectAf);
|
||||
} else if (yFP == iRightFP) {
|
||||
rightMin = Q16Dot16ToInt(qMin(topRightIntersectAf, bottomRightIntersectBf));
|
||||
rightMax = Q16Dot16ToInt(qMin(bottomRightIntersectAf, topRightIntersectBf));
|
||||
rightMin = QScFixedToInt(qMin(topRightIntersectAf, bottomRightIntersectBf));
|
||||
rightMax = QScFixedToInt(qMin(bottomRightIntersectAf, topRightIntersectBf));
|
||||
} else {
|
||||
rightMin = Q16Dot16ToInt(bottomRightIntersectBf);
|
||||
rightMax = Q16Dot16ToInt(topRightIntersectBf);
|
||||
rightMin = QScFixedToInt(bottomRightIntersectBf);
|
||||
rightMax = QScFixedToInt(topRightIntersectBf);
|
||||
}
|
||||
|
||||
rightMin = qBound(d->clipRect.left(), rightMin, d->clipRect.right());
|
||||
|
|
@ -1075,11 +1084,11 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
|
|||
if (rightMin < leftMin)
|
||||
rightMin = leftMin;
|
||||
|
||||
Q16Dot16 rowHeight = rowBottom - rowTop;
|
||||
QScFixed rowHeight = rowBottom - rowTop;
|
||||
|
||||
int x = leftMin;
|
||||
while (x <= leftMax) {
|
||||
Q16Dot16 excluded = 0;
|
||||
QScFixed excluded = 0;
|
||||
|
||||
if (yFP <= iLeftFP)
|
||||
excluded += intersectPixelFP(x, rowTop, rowBottomLeft,
|
||||
|
|
@ -1101,18 +1110,18 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
|
|||
bottomRightSlopeFP, invBottomRightSlopeFP);
|
||||
}
|
||||
|
||||
Q16Dot16 coverage = rowHeight - excluded;
|
||||
buffer.addSpan(x, 1, Q16Dot16ToInt(yFP),
|
||||
Q16Dot16ToInt(255 * coverage));
|
||||
QScFixed coverage = rowHeight - excluded;
|
||||
buffer.addSpan(x, 1, QScFixedToInt(yFP),
|
||||
QScFixedToInt(255 * coverage));
|
||||
++x;
|
||||
}
|
||||
if (x < rightMin) {
|
||||
buffer.addSpan(x, rightMin - x, Q16Dot16ToInt(yFP),
|
||||
Q16Dot16ToInt(255 * rowHeight));
|
||||
buffer.addSpan(x, rightMin - x, QScFixedToInt(yFP),
|
||||
QScFixedToInt(255 * rowHeight));
|
||||
x = rightMin;
|
||||
}
|
||||
while (x <= rightMax) {
|
||||
Q16Dot16 excluded = 0;
|
||||
QScFixed excluded = 0;
|
||||
if (yFP <= iRightFP)
|
||||
excluded += (rowBottomRight - rowTop) - intersectPixelFP(x, rowTop, rowBottomRight,
|
||||
topRightIntersectAf, bottomRightIntersectAf,
|
||||
|
|
@ -1122,9 +1131,9 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
|
|||
bottomRightIntersectBf, topRightIntersectBf,
|
||||
bottomRightSlopeFP, invBottomRightSlopeFP);
|
||||
|
||||
Q16Dot16 coverage = rowHeight - excluded;
|
||||
buffer.addSpan(x, 1, Q16Dot16ToInt(yFP),
|
||||
Q16Dot16ToInt(255 * coverage));
|
||||
QScFixed coverage = rowHeight - excluded;
|
||||
buffer.addSpan(x, 1, QScFixedToInt(yFP),
|
||||
QScFixedToInt(255 * coverage));
|
||||
++x;
|
||||
}
|
||||
|
||||
|
|
@ -1135,7 +1144,7 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
|
|||
topLeftIntersectAf = leftIntersectAf;
|
||||
topRightIntersectAf = rightIntersectAf;
|
||||
|
||||
yFP += Q16Dot16Factor;
|
||||
yFP += QScFixedFactor;
|
||||
rowTop = yFP;
|
||||
}
|
||||
} else { // aliased
|
||||
|
|
@ -1145,10 +1154,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 = qSafeFloatToQ16Dot16(top.x() + 0.5f + (iTop + 0.5f - top.y()) * topLeftSlope);
|
||||
Q16Dot16 leftIntersectBf = qSafeFloatToQ16Dot16(left.x() + 0.5f + (iLeft + 1.5f - left.y()) * bottomLeftSlope);
|
||||
Q16Dot16 rightIntersectAf = qSafeFloatToQ16Dot16(top.x() - 0.5f + (iTop + 0.5f - top.y()) * topRightSlope);
|
||||
Q16Dot16 rightIntersectBf = qSafeFloatToQ16Dot16(right.x() - 0.5f + (iRight + 1.5f - right.y()) * bottomRightSlope);
|
||||
QScFixed leftIntersectAf = qSafeFloatToQScFixed(top.x() + 0.5f + (iTop + 0.5f - top.y()) * topLeftSlope);
|
||||
QScFixed leftIntersectBf = qSafeFloatToQScFixed(left.x() + 0.5f + (iLeft + 1.5f - left.y()) * bottomLeftSlope);
|
||||
QScFixed rightIntersectAf = qSafeFloatToQScFixed(top.x() - 0.5f + (iTop + 0.5f - top.y()) * topRightSlope);
|
||||
QScFixed rightIntersectBf = qSafeFloatToQScFixed(right.x() - 0.5f + (iRight + 1.5f - right.y()) * bottomRightSlope);
|
||||
|
||||
int ny;
|
||||
int y = iTop;
|
||||
|
|
@ -1162,8 +1171,8 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
|
|||
if (next > d->clipRect.bottom()) \
|
||||
next = d->clipRect.bottom(); \
|
||||
for (; y <= next; ++y) { \
|
||||
const int x1 = qMax(Q16Dot16ToInt(li), d->clipRect.left()); \
|
||||
const int x2 = qMin(Q16Dot16ToInt(ri), d->clipRect.right()); \
|
||||
const int x1 = qMax(QScFixedToInt(li), d->clipRect.left()); \
|
||||
const int x2 = qMin(QScFixedToInt(ri), d->clipRect.right()); \
|
||||
if (x2 >= x1) \
|
||||
buffer.addSpan(x1, x2 - x1 + 1, y, 255); \
|
||||
li += ls; \
|
||||
|
|
|
|||
|
|
@ -240,6 +240,9 @@ private slots:
|
|||
|
||||
void wideImage();
|
||||
|
||||
void largeFillScale();
|
||||
void largeRasterScale();
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
void toWinHBITMAP_data();
|
||||
void toWinHBITMAP();
|
||||
|
|
@ -3837,6 +3840,67 @@ void tst_QImage::wideImage()
|
|||
// Qt6: Test that it actually works on 64bit architectures.
|
||||
}
|
||||
|
||||
void tst_QImage::largeFillScale()
|
||||
{
|
||||
#if Q_PROCESSOR_WORDSIZE < 8
|
||||
QSKIP("Test fails on 32-bit builds");
|
||||
#endif
|
||||
// Test from QTBUG-84428
|
||||
QImage input(QSize(std::numeric_limits<qint16>::max() + 10, 1), QImage::Format_ARGB32_Premultiplied);
|
||||
input.fill(Qt::white);
|
||||
|
||||
const int scaleFactor = 2;
|
||||
QImage scaled = input.scaled(input.width(), input.height() * scaleFactor);
|
||||
|
||||
for (int x = 0, w = input.width(); x < w; ++x) {
|
||||
const auto inputPixel = input.pixel(x, 0);
|
||||
auto scaledPixel = scaled.pixel(x, 0);
|
||||
QCOMPARE(scaledPixel, inputPixel);
|
||||
scaledPixel = scaled.pixel(x, 1);
|
||||
QCOMPARE(scaledPixel, inputPixel);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QImage::largeRasterScale()
|
||||
{
|
||||
#if Q_PROCESSOR_WORDSIZE < 8
|
||||
QSKIP("Test fails on 32-bit builds");
|
||||
#endif
|
||||
// Now test that qgrayraster still works at these ranges
|
||||
QImage image(QSize(40000, 200), QImage::Format_RGB32);
|
||||
image.fill(Qt::white);
|
||||
|
||||
QPainter painter(&image);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
painter.setBrush(Qt::black);
|
||||
painter.drawEllipse(QPoint(33000, 100), 6990, 99);
|
||||
painter.end();
|
||||
QCOMPARE(image.pixelColor(27000, 10), Qt::white);
|
||||
QCOMPARE(image.pixelColor(33000, 10), Qt::black);
|
||||
QCOMPARE(image.pixelColor(39000, 10), Qt::white);
|
||||
QCOMPARE(image.pixelColor(27000, 100), Qt::black);
|
||||
QCOMPARE(image.pixelColor(33000, 100), Qt::black);
|
||||
QCOMPARE(image.pixelColor(39000, 100), Qt::black);
|
||||
QCOMPARE(image.pixelColor(27000, 190), Qt::white);
|
||||
QCOMPARE(image.pixelColor(33000, 190), Qt::black);
|
||||
QCOMPARE(image.pixelColor(39000, 190), Qt::white);
|
||||
|
||||
// Now check grayscale antialiasing takes place in the higher coords
|
||||
bool grayObserved = false;
|
||||
for (int x = 33000; x < 39000; ++x) {
|
||||
QRgb pixel = image.pixel(x, 20);
|
||||
if (pixel == 0xff000000)
|
||||
continue; // still black
|
||||
if (pixel == 0xffffffff) {
|
||||
QVERIFY(grayObserved);
|
||||
break;
|
||||
}
|
||||
grayObserved = true;
|
||||
}
|
||||
|
||||
// image.save("largeRasterScale.png", "PNG");
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
|
||||
static inline QColor COLORREFToQColor(COLORREF cr)
|
||||
|
|
|
|||
Loading…
Reference in New Issue