summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/painting/qdrawhelper.cpp192
-rw-r--r--src/gui/painting/qdrawhelper_neon.cpp2
-rw-r--r--src/gui/painting/qdrawhelper_p.h25
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp2
-rw-r--r--tests/auto/gui/painting/qpainter/tst_qpainter.cpp43
5 files changed, 156 insertions, 108 deletions
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index aad904e8fc..138e1ecb3b 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -3441,78 +3441,50 @@ static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const Q
}
}
-static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data,
- int y, int x, int length)
+class GradientBase32
{
- const uint *b = buffer;
- qreal t, inc;
-
- bool affine = true;
- qreal rx=0, ry=0;
- if (op->linear.l == 0) {
- t = inc = 0;
- } else {
- rx = data->m21 * (y + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx;
- ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(0.5)) + data->dy;
- t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off;
- inc = op->linear.dx * data->m11 + op->linear.dy * data->m12;
- affine = !data->m13 && !data->m23;
-
- if (affine) {
- t *= (GRADIENT_STOPTABLE_SIZE - 1);
- inc *= (GRADIENT_STOPTABLE_SIZE - 1);
- }
+public:
+ typedef uint Type;
+ static Type null() { return 0; }
+ static Type fetchSingle(const QGradientData& gradient, qreal v)
+ {
+ return qt_gradient_pixel(&gradient, v);
}
-
- const uint *end = buffer + length;
- if (affine) {
- if (inc > qreal(-1e-5) && inc < qreal(1e-5)) {
- QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE)));
- } else {
- if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) &&
- t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) {
- // we can use fixed point math
- int t_fixed = int(t * FIXPT_SIZE);
- int inc_fixed = int(inc * FIXPT_SIZE);
- while (buffer < end) {
- *buffer = qt_gradient_pixel_fixed(&data->gradient, t_fixed);
- t_fixed += inc_fixed;
- ++buffer;
- }
- } else {
- // we have to fall back to float math
- while (buffer < end) {
- *buffer = qt_gradient_pixel(&data->gradient, t/GRADIENT_STOPTABLE_SIZE);
- t += inc;
- ++buffer;
- }
- }
- }
- } else { // fall back to float math here as well
- qreal rw = data->m23 * (y + qreal(0.5)) + data->m13 * (x + qreal(0.5)) + data->m33;
- while (buffer < end) {
- qreal x = rx/rw;
- qreal y = ry/rw;
- t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off;
-
- *buffer = qt_gradient_pixel(&data->gradient, t);
- rx += data->m11;
- ry += data->m12;
- rw += data->m13;
- if (!rw) {
- rw += data->m13;
- }
- ++buffer;
- }
+ static Type fetchSingle(const QGradientData& gradient, int v)
+ {
+ return qt_gradient_pixel_fixed(&gradient, v);
}
+ static void memfill(Type *buffer, Type fill, int length)
+ {
+ qt_memfill32(buffer, fill, length);
+ }
+};
- return b;
-}
+class GradientBase64
+{
+public:
+ typedef QRgba64 Type;
+ static Type null() { return QRgba64::fromRgba64(0); }
+ static Type fetchSingle(const QGradientData& gradient, qreal v)
+ {
+ return qt_gradient_pixel64(&gradient, v);
+ }
+ static Type fetchSingle(const QGradientData& gradient, int v)
+ {
+ return qt_gradient_pixel64_fixed(&gradient, v);
+ }
+ static void memfill(Type *buffer, Type fill, int length)
+ {
+ qt_memfill64((quint64*)buffer, fill, length);
+ }
+};
-static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data,
- int y, int x, int length)
+template<class GradientBase, typename BlendType>
+static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template(
+ BlendType *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
{
- const QRgba64 *b = buffer;
+ const BlendType *b = buffer;
qreal t, inc;
bool affine = true;
@@ -3532,11 +3504,10 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe
}
}
- const QRgba64 *end = buffer + length;
+ const BlendType *end = buffer + length;
if (affine) {
if (inc > qreal(-1e-5) && inc < qreal(1e-5)) {
- QRgba64 color = qt_gradient_pixel64_fixed(&data->gradient, int(t * FIXPT_SIZE));
- qt_memfill64((quint64*)buffer, color, length);
+ GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, int(t * FIXPT_SIZE)), length);
} else {
if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) &&
t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) {
@@ -3544,14 +3515,14 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe
int t_fixed = int(t * FIXPT_SIZE);
int inc_fixed = int(inc * FIXPT_SIZE);
while (buffer < end) {
- *buffer = qt_gradient_pixel64_fixed(&data->gradient, t_fixed);
+ *buffer = GradientBase::fetchSingle(data->gradient, t_fixed);
t_fixed += inc_fixed;
++buffer;
}
} else {
// we have to fall back to float math
while (buffer < end) {
- *buffer = qt_gradient_pixel64(&data->gradient, t/GRADIENT_STOPTABLE_SIZE);
+ *buffer = GradientBase::fetchSingle(data->gradient, t/GRADIENT_STOPTABLE_SIZE);
t += inc;
++buffer;
}
@@ -3564,7 +3535,7 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe
qreal y = ry/rw;
t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off;
- *buffer = qt_gradient_pixel64(&data->gradient, t);
+ *buffer = GradientBase::fetchSingle(data->gradient, t);
rx += data->m11;
ry += data->m12;
rw += data->m13;
@@ -3578,6 +3549,18 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe
return b;
}
+static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_linear_gradient_template<GradientBase32, uint>(buffer, op, data, y, x, length);
+}
+
+static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_linear_gradient_template<GradientBase64, QRgba64>(buffer, op, data, y, x, length);
+}
+
static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
{
v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x;
@@ -3592,19 +3575,22 @@ static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const Q
v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0;
}
-class RadialFetchPlain
+template <class GradientBase>
+class RadialFetchPlain : public GradientBase
{
public:
- static inline void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det,
- qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b)
+ typedef typename GradientBase::Type BlendType;
+ static void fetch(BlendType *buffer, BlendType *end,
+ const Operator *op, const QSpanData *data, qreal det,
+ qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b)
{
if (op->radial.extended) {
while (buffer < end) {
- quint32 result = 0;
+ BlendType result = GradientBase::null();
if (det >= 0) {
qreal w = qSqrt(det) - b;
if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0)
- result = qt_gradient_pixel(&data->gradient, w);
+ result = GradientBase::fetchSingle(data->gradient, w);
}
*buffer = result;
@@ -3617,7 +3603,7 @@ public:
}
} else {
while (buffer < end) {
- *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b);
+ *buffer++ = GradientBase::fetchSingle(data->gradient, qSqrt(det) - b);
det += delta_det;
delta_det += delta_delta_det;
@@ -3630,15 +3616,23 @@ public:
const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data,
int y, int x, int length)
{
- return qt_fetch_radial_gradient_template<RadialFetchPlain>(buffer, op, data, y, x, length);
+ return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBase32>, uint>(buffer, op, data, y, x, length);
}
static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain;
-static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data,
- int y, int x, int length)
+const QRgba64 * QT_FASTCALL qt_fetch_radial_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBase64>, QRgba64>(buffer, op, data, y, x, length);
+}
+
+template <class GradientBase, typename BlendType>
+static inline const BlendType * QT_FASTCALL qt_fetch_conical_gradient_template(
+ BlendType *buffer, const QSpanData *data,
+ int y, int x, int length)
{
- const uint *b = buffer;
+ const BlendType *b = buffer;
qreal rx = data->m21 * (y + qreal(0.5))
+ data->dx + data->m11 * (x + qreal(0.5));
qreal ry = data->m22 * (y + qreal(0.5))
@@ -3647,14 +3641,14 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op
const qreal inv2pi = M_1_PI / 2.0;
- const uint *end = buffer + length;
+ const BlendType *end = buffer + length;
if (affine) {
rx -= data->gradient.conical.center.x;
ry -= data->gradient.conical.center.y;
while (buffer < end) {
qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle;
- *buffer = qt_gradient_pixel(&data->gradient, 1 - angle * inv2pi);
+ *buffer = GradientBase::fetchSingle(data->gradient, 1 - angle * inv2pi);
rx += data->m11;
ry += data->m12;
@@ -3670,7 +3664,7 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op
rx/rw - data->gradient.conical.center.y)
+ data->gradient.conical.angle;
- *buffer = qt_gradient_pixel(&data->gradient, 1 - angle * inv2pi);
+ *buffer = GradientBase::fetchSingle(data->gradient, 1 - angle * inv2pi);
rx += data->m11;
ry += data->m12;
@@ -3684,6 +3678,18 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op
return b;
}
+static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_conical_gradient_template<GradientBase32, uint>(buffer, data, y, x, length);
+}
+
+static const QRgba64 * QT_FASTCALL qt_fetch_conical_gradient_rgb64(QRgba64 *buffer, const Operator *, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_conical_gradient_template<GradientBase64, QRgba64>(buffer, data, y, x, length);
+}
+
# define PRELOAD_INIT(x)
# define PRELOAD_INIT2(x,y)
# define PRELOAD_COND(x)
@@ -5876,6 +5882,8 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
switch(data->type) {
case QSpanData::Solid:
solidSource = data->solid.color.isOpaque();
+ op.srcFetch = 0;
+ op.srcFetch64 = 0;
break;
case QSpanData::LinearGradient:
solidSource = !data->gradient.alphaColor;
@@ -5887,18 +5895,20 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
solidSource = !data->gradient.alphaColor;
getRadialGradientValues(&op.radial, data);
op.srcFetch = qt_fetch_radial_gradient;
- op.srcFetch64 = 0; //qt_fetch_radial_gradient_rgb64;
+ op.srcFetch64 = qt_fetch_radial_gradient_rgb64;
break;
case QSpanData::ConicalGradient:
solidSource = !data->gradient.alphaColor;
op.srcFetch = qt_fetch_conical_gradient;
- op.srcFetch64 = 0; //qt_fetch_conical_gradient_rgb64;
+ op.srcFetch64 = qt_fetch_conical_gradient_rgb64;
break;
case QSpanData::Texture:
+ solidSource = !data->texture.hasAlpha;
op.srcFetch = sourceFetch[getBlendType(data)][data->texture.format];
op.srcFetch64 = sourceFetch64[getBlendType(data)][data->texture.format];
- solidSource = !data->texture.hasAlpha;
+ break;
default:
+ Q_UNREACHABLE();
break;
}
@@ -6212,7 +6222,7 @@ public:
bool isSupported() const
{
- return op.srcFetch64 && op.func64 && op.destFetch64 && op.destStore64;
+ return op.func64 && op.destFetch64 && op.destStore64;
}
const QRgba64 *fetch(int x, int y, int len)
@@ -6303,7 +6313,7 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
Operator op = getOperator(data, spans, count);
- if (!op.srcFetch64 || !op.func64) {
+ if (!op.func64) {
qWarning() << Q_FUNC_INFO << "Unsupported blend";
return blend_untransformed_generic(count, spans, userData);
}
@@ -6544,7 +6554,7 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
Operator op = getOperator(data, spans, count);
- if (!op.srcFetch64 || !op.func64) {
+ if (!op.func64) {
qDebug("unsupported rgb64 blend");
return blend_tiled_generic(count, spans, userData);
}
diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp
index 36e2488a94..08e564f017 100644
--- a/src/gui/painting/qdrawhelper_neon.cpp
+++ b/src/gui/painting/qdrawhelper_neon.cpp
@@ -986,7 +986,7 @@ public:
const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data,
int y, int x, int length)
{
- return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdNeon> >(buffer, op, data, y, x, length);
+ return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdNeon>,uint>(buffer, op, data, y, x, length);
}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index 53f4db6fce..d584e392e9 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -395,24 +395,24 @@ static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c)
return (b * b) - (4 * a * c);
}
-template <class RadialFetchFunc> Q_STATIC_TEMPLATE_FUNCTION
-const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data,
- int y, int x, int length)
+template <class RadialFetchFunc, typename BlendType> static
+const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffer, const Operator *op,
+ const QSpanData *data, int y, int x, int length)
{
// avoid division by zero
if (qFuzzyIsNull(op->radial.a)) {
- qt_memfill32(buffer, 0, length);
+ RadialFetchFunc::memfill(buffer, RadialFetchFunc::null(), length);
return buffer;
}
- const uint *b = buffer;
+ const BlendType *b = buffer;
qreal rx = data->m21 * (y + qreal(0.5))
+ data->dx + data->m11 * (x + qreal(0.5));
qreal ry = data->m22 * (y + qreal(0.5))
+ data->dy + data->m12 * (x + qreal(0.5));
bool affine = !data->m13 && !data->m23;
- uint *end = buffer + length;
+ BlendType *end = buffer + length;
if (affine) {
rx -= data->gradient.radial.focal.x;
ry -= data->gradient.radial.focal.y;
@@ -459,7 +459,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O
qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + gx*op->radial.dx + gy*op->radial.dy);
qreal det = qRadialDeterminant(op->radial.a, b, op->radial.sqrfr - (gx*gx + gy*gy));
- quint32 result = 0;
+ BlendType result = RadialFetchFunc::null();
if (det >= 0) {
qreal detSqrt = qSqrt(det);
@@ -469,7 +469,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O
qreal s = qMax(s0, s1);
if (data->gradient.radial.focal.radius + op->radial.dr * s >= 0)
- result = qt_gradient_pixel(&data->gradient, s);
+ result = RadialFetchFunc::fetchSingle(data->gradient, s);
}
*buffer = result;
@@ -490,6 +490,15 @@ template <class Simd>
class QRadialFetchSimd
{
public:
+ static uint null() { return 0; }
+ static uint fetchSingle(const QGradientData& gradient, qreal v)
+ {
+ return qt_gradient_pixel(&gradient, v);
+ }
+ static void memfill(uint *buffer, uint fill, int length)
+ {
+ qt_memfill32(buffer, fill, length);
+ }
static void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det,
qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b)
{
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index b8957fe2fb..17e9d462fd 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -550,7 +550,7 @@ public:
const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
int y, int x, int length)
{
- return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdSse2> >(buffer, op, data, y, x, length);
+ return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdSse2>,uint>(buffer, op, data, y, x, length);
}
void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
index 3c5fcba06e..53e9ad6f20 100644
--- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
+++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
@@ -203,8 +203,10 @@ private slots:
void gradientPixelFormat_data();
void gradientPixelFormat();
- void gradientRgb30_data();
- void gradientRgb30();
+ void linearGradientRgb30_data();
+ void linearGradientRgb30();
+ void radialGradientRgb30_data();
+ void radialGradientRgb30();
void fpe_pixmapTransform();
void fpe_zeroLengthLines();
@@ -3952,7 +3954,7 @@ void tst_QPainter::gradientInterpolation()
}
}
-void tst_QPainter::gradientRgb30_data()
+void tst_QPainter::linearGradientRgb30_data()
{
QTest::addColumn<QColor>("stop0");
QTest::addColumn<QColor>("stop1");
@@ -3962,21 +3964,48 @@ void tst_QPainter::gradientRgb30_data()
QTest::newRow("white->red") << QColor(Qt::white) << QColor(Qt::red);
}
-void tst_QPainter::gradientRgb30()
+void tst_QPainter::linearGradientRgb30()
{
QFETCH(QColor, stop0);
QFETCH(QColor, stop1);
- QLinearGradient gradient(0, 0, 512, 1);
+ QLinearGradient gradient(0, 0, 1000, 1);
gradient.setColorAt(0.0, stop0);
gradient.setColorAt(1.0, stop1);
- QImage image(512, 1, QImage::Format_RGB30);
+ QImage image(1000, 1, QImage::Format_RGB30);
QPainter painter(&image);
painter.fillRect(image.rect(), gradient);
painter.end();
- for (int i = 0; i < 511; ++i) {
+ for (int i = 0; i < 1000; ++i) {
+ QColor p1 = image.pixelColor(i, 0);
+ QColor p2 = image.pixelColor(i + 1, 0);
+ QVERIFY(p1 != p2);
+ QVERIFY(qGray(p1.rgb()) >= qGray(p2.rgb()));
+ }
+}
+
+void tst_QPainter::radialGradientRgb30_data()
+{
+ linearGradientRgb30_data();
+}
+
+void tst_QPainter::radialGradientRgb30()
+{
+ QFETCH(QColor, stop0);
+ QFETCH(QColor, stop1);
+
+ QRadialGradient gradient(0, 0, 1000);
+ gradient.setColorAt(0.0, stop0);
+ gradient.setColorAt(1.0, stop1);
+
+ QImage image(1000, 1, QImage::Format_A2BGR30_Premultiplied);
+ QPainter painter(&image);
+ painter.fillRect(image.rect(), gradient);
+ painter.end();
+
+ for (int i = 0; i < 1000; ++i) {
QColor p1 = image.pixelColor(i, 0);
QColor p2 = image.pixelColor(i + 1, 0);
QVERIFY(p1 != p2);