summaryrefslogtreecommitdiffstats
path: root/src/gui/painting
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2011-04-28 18:47:18 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2011-04-28 18:47:18 (GMT)
commitbc0d5838a3bb884c1de782145ce0d8501710c883 (patch)
treebccda364e78f28424f8481aea498847f5a1a9eb4 /src/gui/painting
parent5bda8bf138d4dab5d31496a8472044ad34589d3f (diff)
parentb3f06ba0dbe2cddcd30d2176ed4dccbc7b3414b0 (diff)
downloadQt-bc0d5838a3bb884c1de782145ce0d8501710c883.zip
Qt-bc0d5838a3bb884c1de782145ce0d8501710c883.tar.gz
Qt-bc0d5838a3bb884c1de782145ce0d8501710c883.tar.bz2
Merge branch 'master' of scm.dev.nokia.troll.no:qt/qt-fire-staging into master-integration
* 'master' of scm.dev.nokia.troll.no:qt/qt-fire-staging: (31 commits) Make QtQuick2 compile on QPA Use maximum ascent/descent/leading from fallback fonts in shaping Another ugly hack to make bidi cursor work with Core Text Make sure layoutData exist before checking for string direction Removed warning from QPixmap::handle(). Take leading space width into account for painting and selection doc: Simplify language in QGlyphs docs doc: Minor cleanup in QGlyphs docs Remove extra comma at the end of enum list Fix compilation with Qt3Support Don't transform glyph positions for Core Graphics paint engine Skip linearGradientSymmetry test on QWS. Turn on HarfBuzz support for Mac/Cocoa Support visual cursor movement for BIDI text Disable tst_QPixmap::onlyNullPixmapsOutsideGuiThread on Mac Revert "Switch the default graphics system to raster on Mac." Fix an race condition in the auto test. Made linearGradientSymmetry test pass on qreal=float platforms. Make sure #ifdef'd tests still have main() function Long live QRawFont! ...
Diffstat (limited to 'src/gui/painting')
-rw-r--r--src/gui/painting/qbrush.cpp191
-rw-r--r--src/gui/painting/qbrush.h12
-rw-r--r--src/gui/painting/qdrawhelper.cpp238
-rw-r--r--src/gui/painting/qdrawhelper_neon.cpp40
-rw-r--r--src/gui/painting/qdrawhelper_p.h258
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp52
-rw-r--r--src/gui/painting/qpaintengine_mac.cpp3
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp81
-rw-r--r--src/gui/painting/qpaintengineex.cpp46
-rw-r--r--src/gui/painting/qpainter.cpp19
-rw-r--r--src/gui/painting/qpainter.h1
-rw-r--r--src/gui/painting/qunifiedtoolbarsurface_mac.cpp3
12 files changed, 734 insertions, 210 deletions
diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp
index bf5764a..3ff7eb8 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -840,6 +840,22 @@ const QGradient *QBrush::gradient() const
return 0;
}
+Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush)
+{
+ if (brush.style() == Qt::RadialGradientPattern) {
+ const QGradient *g = brush.gradient();
+ const QRadialGradient *rg = static_cast<const QRadialGradient *>(g);
+
+ if (!qFuzzyIsNull(rg->focalRadius()))
+ return true;
+
+ QPointF delta = rg->focalPoint() - rg->center();
+ if (delta.x() * delta.x() + delta.y() * delta.y() > rg->radius() * rg->radius())
+ return true;
+ }
+
+ return false;
+}
/*!
Returns true if the brush is fully opaque otherwise false. A brush
@@ -849,6 +865,7 @@ const QGradient *QBrush::gradient() const
\i The alpha component of the color() is 255.
\i Its texture() does not have an alpha channel and is not a QBitmap.
\i The colors in the gradient() all have an alpha component that is 255.
+ \i It is an extended radial gradient.
\endlist
*/
@@ -860,6 +877,9 @@ bool QBrush::isOpaque() const
if (d->style == Qt::SolidPattern)
return opaqueColor;
+ if (qt_isExtendedRadialGradient(*this))
+ return false;
+
if (d->style == Qt::LinearGradientPattern
|| d->style == Qt::RadialGradientPattern
|| d->style == Qt::ConicalGradientPattern) {
@@ -1209,8 +1229,10 @@ QDataStream &operator>>(QDataStream &s, QBrush &b)
\list
\o \e Linear gradients interpolate colors between start and end points.
- \o \e Radial gradients interpolate colors between a focal point and end
- points on a circle surrounding it.
+ \o \e Simple radial gradients interpolate colors between a focal point
+ and end points on a circle surrounding it.
+ \o \e Extended radial gradients interpolate colors between a center and
+ a focal circle.
\o \e Conical gradients interpolate colors around a center point.
\endlist
@@ -1506,8 +1528,6 @@ void QGradient::setInterpolationMode(InterpolationMode mode)
dummy = p;
}
-#undef Q_DUMMY_ACCESSOR
-
/*!
\fn bool QGradient::operator!=(const QGradient &gradient) const
\since 4.2
@@ -1541,7 +1561,7 @@ bool QGradient::operator==(const QGradient &gradient) const
|| m_data.radial.cy != gradient.m_data.radial.cy
|| m_data.radial.fx != gradient.m_data.radial.fx
|| m_data.radial.fy != gradient.m_data.radial.fy
- || m_data.radial.radius != gradient.m_data.radial.radius)
+ || m_data.radial.cradius != gradient.m_data.radial.cradius)
return false;
} else { // m_type == ConicalGradient
if (m_data.conical.cx != gradient.m_data.conical.cx
@@ -1747,10 +1767,17 @@ void QLinearGradient::setFinalStop(const QPointF &stop)
\brief The QRadialGradient class is used in combination with QBrush to
specify a radial gradient brush.
- Radial gradients interpolate colors between a focal point and end
- points on a circle surrounding it. Outside the end points the
- gradient is either padded, reflected or repeated depending on the
- currently set \l {QGradient::Spread}{spread} method:
+ Qt supports both simple and extended radial gradients.
+
+ Simple radial gradients interpolate colors between a focal point and end
+ points on a circle surrounding it. Extended radial gradients interpolate
+ colors between a focal circle and a center circle. Points outside the cone
+ defined by the two circles will be transparent. For simple radial gradients
+ the focal point is adjusted to lie inside the center circle, whereas the
+ focal point can have any position in an extended radial gradient.
+
+ Outside the end points the gradient is either padded, reflected or repeated
+ depending on the currently set \l {QGradient::Spread}{spread} method:
\table
\row
@@ -1795,9 +1822,14 @@ static QPointF qt_radial_gradient_adapt_focal_point(const QPointF &center,
}
/*!
- Constructs a radial gradient with the given \a center, \a
+ Constructs a simple radial gradient with the given \a center, \a
radius and \a focalPoint.
+ \note If the given focal point is outside the circle defined by the
+ center (\a cx, \a cy) and the \a radius it will be re-adjusted to
+ the intersection between the line from the center to the focal point
+ and the circle.
+
\sa QGradient::setColorAt(), QGradient::setStops()
*/
@@ -1807,7 +1839,7 @@ QRadialGradient::QRadialGradient(const QPointF &center, qreal radius, const QPoi
m_spread = PadSpread;
m_data.radial.cx = center.x();
m_data.radial.cy = center.y();
- m_data.radial.radius = radius;
+ m_data.radial.cradius = radius;
QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(center, radius, focalPoint);
m_data.radial.fx = adapted_focal.x();
@@ -1815,7 +1847,7 @@ QRadialGradient::QRadialGradient(const QPointF &center, qreal radius, const QPoi
}
/*!
- Constructs a radial gradient with the given \a center, \a
+ Constructs a simple radial gradient with the given \a center, \a
radius and the focal point in the circle center.
\sa QGradient::setColorAt(), QGradient::setStops()
@@ -1826,16 +1858,21 @@ QRadialGradient::QRadialGradient(const QPointF &center, qreal radius)
m_spread = PadSpread;
m_data.radial.cx = center.x();
m_data.radial.cy = center.y();
- m_data.radial.radius = radius;
+ m_data.radial.cradius = radius;
m_data.radial.fx = center.x();
m_data.radial.fy = center.y();
}
/*!
- Constructs a radial gradient with the given center (\a cx, \a cy),
+ Constructs a simple radial gradient with the given center (\a cx, \a cy),
\a radius and focal point (\a fx, \a fy).
+ \note If the given focal point is outside the circle defined by the
+ center (\a cx, \a cy) and the \a radius it will be re-adjusted to
+ the intersection between the line from the center to the focal point
+ and the circle.
+
\sa QGradient::setColorAt(), QGradient::setStops()
*/
@@ -1845,7 +1882,7 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qre
m_spread = PadSpread;
m_data.radial.cx = cx;
m_data.radial.cy = cy;
- m_data.radial.radius = radius;
+ m_data.radial.cradius = radius;
QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(QPointF(cx, cy),
radius,
@@ -1856,7 +1893,7 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qre
}
/*!
- Constructs a radial gradient with the center at (\a cx, \a cy) and the
+ Constructs a simple radial gradient with the center at (\a cx, \a cy) and the
specified \a radius. The focal point lies at the center of the circle.
\sa QGradient::setColorAt(), QGradient::setStops()
@@ -1867,14 +1904,14 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius)
m_spread = PadSpread;
m_data.radial.cx = cx;
m_data.radial.cy = cy;
- m_data.radial.radius = radius;
+ m_data.radial.cradius = radius;
m_data.radial.fx = cx;
m_data.radial.fy = cy;
}
/*!
- Constructs a radial gradient with the center and focal point at
+ Constructs a simple radial gradient with the center and focal point at
(0, 0) with a radius of 1.
*/
QRadialGradient::QRadialGradient()
@@ -1883,11 +1920,51 @@ QRadialGradient::QRadialGradient()
m_spread = PadSpread;
m_data.radial.cx = 0;
m_data.radial.cy = 0;
- m_data.radial.radius = 1;
+ m_data.radial.cradius = 1;
m_data.radial.fx = 0;
m_data.radial.fy = 0;
}
+/*!
+ \since 4.8
+
+ Constructs an extended radial gradient with the given \a center, \a
+ centerRadius, \a focalPoint, and \a focalRadius.
+*/
+QRadialGradient::QRadialGradient(const QPointF &center, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius)
+{
+ m_type = RadialGradient;
+ m_spread = PadSpread;
+ m_data.radial.cx = center.x();
+ m_data.radial.cy = center.y();
+ m_data.radial.cradius = centerRadius;
+
+ m_data.radial.fx = focalPoint.x();
+ m_data.radial.fy = focalPoint.y();
+ setFocalRadius(focalRadius);
+}
+
+/*!
+ \since 4.8
+
+ Constructs an extended radial gradient with the given \a center, \a
+ centerRadius, \a focalPoint, and \a focalRadius.
+ Constructs a radial gradient with the given center (\a cx, \a cy),
+ center radius \a centerRadius, focal point (\a fx, \a fy), and
+ focal radius \a focalRadius.
+*/
+QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius)
+{
+ m_type = RadialGradient;
+ m_spread = PadSpread;
+ m_data.radial.cx = cx;
+ m_data.radial.cy = cy;
+ m_data.radial.cradius = centerRadius;
+
+ m_data.radial.fx = fx;
+ m_data.radial.fy = fy;
+ setFocalRadius(focalRadius);
+}
/*!
Returns the center of this radial gradient in logical coordinates.
@@ -1932,13 +2009,15 @@ void QRadialGradient::setCenter(const QPointF &center)
/*!
Returns the radius of this radial gradient in logical coordinates.
+ Equivalent to centerRadius()
+
\sa QGradient::stops()
*/
qreal QRadialGradient::radius() const
{
Q_ASSERT(m_type == RadialGradient);
- return m_data.radial.radius;
+ return m_data.radial.cradius;
}
@@ -1947,13 +2026,81 @@ qreal QRadialGradient::radius() const
Sets the radius of this radial gradient in logical coordinates
to \a radius
+
+ Equivalent to setCenterRadius()
*/
void QRadialGradient::setRadius(qreal radius)
{
Q_ASSERT(m_type == RadialGradient);
- m_data.radial.radius = radius;
+ m_data.radial.cradius = radius;
+}
+
+/*!
+ \since 4.8
+
+ Returns the center radius of this radial gradient in logical
+ coordinates.
+
+ \sa QGradient::stops()
+*/
+qreal QRadialGradient::centerRadius() const
+{
+ Q_ASSERT(m_type == RadialGradient);
+ return m_data.radial.cradius;
+}
+
+/*
+ \since 4.8
+
+ Sets the center radius of this radial gradient in logical coordinates
+ to \a radius
+*/
+void QRadialGradient::setCenterRadius(qreal radius)
+{
+ Q_ASSERT(m_type == RadialGradient);
+ m_data.radial.cradius = radius;
+}
+
+/*!
+ \since 4.8
+
+ Returns the focal radius of this radial gradient in logical
+ coordinates.
+
+ \sa QGradient::stops()
+*/
+qreal QRadialGradient::focalRadius() const
+{
+ Q_ASSERT(m_type == RadialGradient);
+ Q_DUMMY_ACCESSOR
+
+ // mask away low three bits
+ union { float f; quint32 i; } u;
+ u.i = i & ~0x07;
+ return u.f;
}
+/*
+ \since 4.8
+
+ Sets the focal radius of this radial gradient in logical coordinates
+ to \a radius
+*/
+void QRadialGradient::setFocalRadius(qreal radius)
+{
+ Q_ASSERT(m_type == RadialGradient);
+ Q_DUMMY_ACCESSOR
+
+ // Since there's no QGradientData, we only have the dummy void * to
+ // store additional data in. The three lowest bits are already
+ // taken, thus we cut the three lowest bits from the significand
+ // and store the radius as a float.
+ union { float f; quint32 i; } u;
+ u.f = float(radius);
+ // add 0x04 to round up when we drop the three lowest bits
+ i |= (u.i + 0x04) & ~0x07;
+ dummy = p;
+}
/*!
Returns the focal point of this radial gradient in logical
@@ -2193,4 +2340,6 @@ void QConicalGradient::setAngle(qreal angle)
\sa setTransform()
*/
+#undef Q_DUMMY_ACCESSOR
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h
index 8b31319..d914c8c 100644
--- a/src/gui/painting/qbrush.h
+++ b/src/gui/painting/qbrush.h
@@ -255,6 +255,7 @@ private:
friend class QLinearGradient;
friend class QRadialGradient;
friend class QConicalGradient;
+ friend class QBrush;
Type m_type;
Spread m_spread;
@@ -264,7 +265,7 @@ private:
qreal x1, y1, x2, y2;
} linear;
struct {
- qreal cx, cy, fx, fy, radius;
+ qreal cx, cy, fx, fy, cradius;
} radial;
struct {
qreal cx, cy, angle;
@@ -303,6 +304,9 @@ public:
QRadialGradient(const QPointF &center, qreal radius);
QRadialGradient(qreal cx, qreal cy, qreal radius);
+ QRadialGradient(const QPointF &center, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius);
+ QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius);
+
QPointF center() const;
void setCenter(const QPointF &center);
inline void setCenter(qreal x, qreal y) { setCenter(QPointF(x, y)); }
@@ -313,6 +317,12 @@ public:
qreal radius() const;
void setRadius(qreal radius);
+
+ qreal centerRadius() const;
+ void setCenterRadius(qreal radius);
+
+ qreal focalRadius() const;
+ void setFocalRadius(qreal radius);
};
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 5e75e4a..ae9993e 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -75,43 +75,9 @@ enum {
fixed_scale = 1 << 16,
half_point = 1 << 15
};
-static const int buffer_size = 2048;
-
-struct LinearGradientValues
-{
- qreal dx;
- qreal dy;
- qreal l;
- qreal off;
-};
-
-struct RadialGradientValues
-{
- qreal dx;
- qreal dy;
- qreal a;
-};
-
-struct Operator;
-typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
-typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length);
-typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
-
-struct Operator
-{
- QPainter::CompositionMode mode;
- DestFetchProc dest_fetch;
- DestStoreProc dest_store;
- SourceFetchProc src_fetch;
- CompositionFunctionSolid funcSolid;
- CompositionFunction func;
- union {
- LinearGradientValues linear;
- RadialGradientValues radial;
-// TextureValues texture;
- };
-};
+// must be multiple of 4 for easier SIMD implementations
+static const int buffer_size = 2048;
/*
Destination fetch. This is simple as we don't have to do bounds checks or
@@ -1346,64 +1312,13 @@ static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = {
},
};
-
-static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos)
-{
- int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5));
-
- // calculate the actual offset.
- if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
- if (data->spread == QGradient::RepeatSpread) {
- ipos = ipos % GRADIENT_STOPTABLE_SIZE;
- ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
-
- } else if (data->spread == QGradient::ReflectSpread) {
- const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
- ipos = ipos % limit;
- ipos = ipos < 0 ? limit + ipos : ipos;
- ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
-
- } else {
- if (ipos < 0) ipos = 0;
- else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
- }
- }
-
- Q_ASSERT(ipos >= 0);
- Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
-
- return data->colorTable[ipos];
-}
-
#define FIXPT_BITS 8
#define FIXPT_SIZE (1<<FIXPT_BITS)
static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
{
int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
-
- // calculate the actual offset.
- if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
- if (data->spread == QGradient::RepeatSpread) {
- ipos = ipos % GRADIENT_STOPTABLE_SIZE;
- ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
-
- } else if (data->spread == QGradient::ReflectSpread) {
- const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
- ipos = ipos % limit;
- ipos = ipos < 0 ? limit + ipos : ipos;
- ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
-
- } else {
- if (ipos < 0) ipos = 0;
- else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
- }
- }
-
- Q_ASSERT(ipos >= 0);
- Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
-
- return data->colorTable[ipos];
+ return data->colorTable[qt_gradient_clamp(data, ipos)];
}
static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
@@ -1419,8 +1334,8 @@ static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const Q
}
}
-static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator *op, const QSpanData *data,
- int y, int x, int length)
+static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
{
const uint *b = buffer;
qreal t, inc;
@@ -1487,110 +1402,65 @@ static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator
return b;
}
-static inline qreal determinant(qreal a, qreal b, qreal c)
-{
- return (b * b) - (4 * a * c);
-}
-
-// function to evaluate real roots
-static inline qreal realRoots(qreal a, qreal b, qreal detSqrt)
-{
- return (-b + detSqrt)/(2 * a);
-}
-
-static inline qreal qSafeSqrt(qreal x)
-{
- return x > 0 ? qSqrt(x) : 0;
-}
-
static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
{
v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x;
v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y;
- v->a = data->gradient.radial.radius*data->gradient.radial.radius - v->dx*v->dx - v->dy*v->dy;
-}
-
-static const uint * QT_FASTCALL fetchRadialGradient(uint *buffer, const Operator *op, const QSpanData *data,
- int y, int x, int length)
-{
- const uint *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;
- //qreal r = data->gradient.radial.radius;
-
- const uint *end = buffer + length;
- if (affine) {
- rx -= data->gradient.radial.focal.x;
- ry -= data->gradient.radial.focal.y;
-
- qreal inv_a = 1 / qreal(2 * op->radial.a);
-
- const qreal delta_rx = data->m11;
- const qreal delta_ry = data->m12;
- qreal b = 2*(rx * op->radial.dx + ry * op->radial.dy);
- qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy);
- const qreal b_delta_b = 2 * b * delta_b;
- const qreal delta_b_delta_b = 2 * delta_b * delta_b;
+ v->dr = data->gradient.radial.center.radius - data->gradient.radial.focal.radius;
+ v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius;
- const qreal bb = b * b;
- const qreal delta_bb = delta_b * delta_b;
+ v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy;
+ v->inv2a = 1 / (2 * v->a);
- b *= inv_a;
- delta_b *= inv_a;
-
- const qreal rxrxryry = rx * rx + ry * ry;
- const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry;
- const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry);
- const qreal delta_rx_plus_ry = 2 * delta_rxrxryry;
-
- inv_a *= inv_a;
+ v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0;
+}
- qreal det = (bb + 4 * op->radial.a * rxrxryry) * inv_a;
- qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a;
- const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a;
+class RadialFetchPlain
+{
+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)
+ {
+ if (op->radial.extended) {
+ while (buffer < end) {
+ quint32 result = 0;
+ 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);
+ }
- while (buffer < end) {
- *buffer = qt_gradient_pixel(&data->gradient, qSafeSqrt(det) - b);
+ *buffer = result;
- det += delta_det;
- delta_det += delta_delta_det;
- b += delta_b;
+ det += delta_det;
+ delta_det += delta_delta_det;
+ b += delta_b;
- ++buffer;
- }
- } else {
- qreal rw = data->m23 * (y + qreal(0.5))
- + data->m33 + data->m13 * (x + qreal(0.5));
- if (!rw)
- rw = 1;
- while (buffer < end) {
- qreal gx = rx/rw - data->gradient.radial.focal.x;
- qreal gy = ry/rw - data->gradient.radial.focal.y;
- qreal b = 2*(gx*op->radial.dx + gy*op->radial.dy);
- qreal det = determinant(op->radial.a, b , -(gx*gx + gy*gy));
- qreal s = realRoots(op->radial.a, b, qSafeSqrt(det));
-
- *buffer = qt_gradient_pixel(&data->gradient, s);
+ ++buffer;
+ }
+ } else {
+ while (buffer < end) {
+ *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b);
- rx += data->m11;
- ry += data->m12;
- rw += data->m13;
- if (!rw) {
- rw += data->m13;
+ det += delta_det;
+ delta_det += delta_delta_det;
+ b += delta_b;
}
- ++buffer;
}
}
+};
- return b;
+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);
}
-static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operator *, const QSpanData *data,
- int y, int x, int 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 uint *b = buffer;
qreal rx = data->m21 * (y + qreal(0.5))
@@ -3347,16 +3217,16 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
case QSpanData::LinearGradient:
solidSource = !data->gradient.alphaColor;
getLinearGradientValues(&op.linear, data);
- op.src_fetch = fetchLinearGradient;
+ op.src_fetch = qt_fetch_linear_gradient;
break;
case QSpanData::RadialGradient:
solidSource = !data->gradient.alphaColor;
getRadialGradientValues(&op.radial, data);
- op.src_fetch = fetchRadialGradient;
+ op.src_fetch = qt_fetch_radial_gradient;
break;
case QSpanData::ConicalGradient:
solidSource = !data->gradient.alphaColor;
- op.src_fetch = fetchConicalGradient;
+ op.src_fetch = qt_fetch_conical_gradient;
break;
case QSpanData::Texture:
op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format];
@@ -7888,6 +7758,11 @@ void qInitDrawhelperAsm()
qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
+
+ extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length);
+
+ qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2;
}
#ifdef QT_HAVE_SSSE3
@@ -7983,6 +7858,11 @@ void qInitDrawhelperAsm()
qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
qt_memfill32 = qt_memfill32_neon;
+
+ extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length);
+
+ qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon;
}
#endif
diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp
index debca37..e673dd9 100644
--- a/src/gui/painting/qdrawhelper_neon.cpp
+++ b/src/gui/painting/qdrawhelper_neon.cpp
@@ -955,6 +955,46 @@ void qt_memrotate270_16_neon(const uchar *srcPixels, int w, int h,
}
}
+class QSimdNeon
+{
+public:
+ typedef int32x4_t Int32x4;
+ typedef float32x4_t Float32x4;
+
+ union Vect_buffer_i { Int32x4 v; int i[4]; };
+ union Vect_buffer_f { Float32x4 v; float f[4]; };
+
+ static inline Float32x4 v_dup(float x) { return vdupq_n_f32(x); }
+ static inline Int32x4 v_dup(int x) { return vdupq_n_s32(x); }
+ static inline Int32x4 v_dup(uint x) { return vdupq_n_s32(x); }
+
+ static inline Float32x4 v_add(Float32x4 a, Float32x4 b) { return vaddq_f32(a, b); }
+ static inline Int32x4 v_add(Int32x4 a, Int32x4 b) { return vaddq_s32(a, b); }
+
+ static inline Float32x4 v_max(Float32x4 a, Float32x4 b) { return vmaxq_f32(a, b); }
+ static inline Float32x4 v_min(Float32x4 a, Float32x4 b) { return vminq_f32(a, b); }
+ static inline Int32x4 v_min_16(Int32x4 a, Int32x4 b) { return vminq_s32(a, b); }
+
+ static inline Int32x4 v_and(Int32x4 a, Int32x4 b) { return vandq_s32(a, b); }
+
+ static inline Float32x4 v_sub(Float32x4 a, Float32x4 b) { return vsubq_f32(a, b); }
+ static inline Int32x4 v_sub(Int32x4 a, Int32x4 b) { return vsubq_s32(a, b); }
+
+ static inline Float32x4 v_mul(Float32x4 a, Float32x4 b) { return vmulq_f32(a, b); }
+
+ static inline Float32x4 v_sqrt(Float32x4 x) { Float32x4 y = vrsqrteq_f32(x); y = vmulq_f32(y, vrsqrtsq_f32(x, vmulq_f32(y, y))); return vmulq_f32(x, y); }
+
+ static inline Int32x4 v_toInt(Float32x4 x) { return vcvtq_s32_f32(x); }
+
+ static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return vcge_f32(a, b); }
+};
+
+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);
+}
+
QT_END_NAMESPACE
#endif // QT_HAVE_NEON
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index d4e731b..e93d736 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -63,6 +63,7 @@
#endif
#include "private/qrasterdefs_p.h"
#include <private/qsimd_p.h>
+#include <private/qmath_p.h>
#ifdef Q_WS_QWS
#include "QtGui/qscreen_qws.h"
@@ -178,6 +179,44 @@ void qBlendTextureCallback(int count, const QSpan *spans, void *userData);
typedef void (QT_FASTCALL *CompositionFunction)(uint *dest, const uint *src, int length, uint const_alpha);
typedef void (QT_FASTCALL *CompositionFunctionSolid)(uint *dest, int length, uint color, uint const_alpha);
+struct LinearGradientValues
+{
+ qreal dx;
+ qreal dy;
+ qreal l;
+ qreal off;
+};
+
+struct RadialGradientValues
+{
+ qreal dx;
+ qreal dy;
+ qreal dr;
+ qreal sqrfr;
+ qreal a;
+ qreal inv2a;
+ bool extended;
+};
+
+struct Operator;
+typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
+typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length);
+typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
+
+struct Operator
+{
+ QPainter::CompositionMode mode;
+ DestFetchProc dest_fetch;
+ DestStoreProc dest_store;
+ SourceFetchProc src_fetch;
+ CompositionFunctionSolid funcSolid;
+ CompositionFunction func;
+ union {
+ LinearGradientValues linear;
+ RadialGradientValues radial;
+ };
+};
+
void qInitDrawhelperAsm();
class QRasterPaintEngine;
@@ -204,12 +243,13 @@ struct QRadialGradientData
struct {
qreal x;
qreal y;
+ qreal radius;
} center;
struct {
qreal x;
qreal y;
+ qreal radius;
} focal;
- qreal radius;
};
struct QConicalGradientData
@@ -233,8 +273,10 @@ struct QGradientData
#ifdef Q_WS_QWS
#define GRADIENT_STOPTABLE_SIZE 256
+#define GRADIENT_STOPTABLE_SIZE_SHIFT 8
#else
#define GRADIENT_STOPTABLE_SIZE 1024
+#define GRADIENT_STOPTABLE_SIZE_SHIFT 10
#endif
uint* colorTable; //[GRADIENT_STOPTABLE_SIZE];
@@ -308,6 +350,220 @@ struct QSpanData
void adjustSpanMethods();
};
+static inline uint qt_gradient_clamp(const QGradientData *data, int ipos)
+{
+ if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
+ if (data->spread == QGradient::RepeatSpread) {
+ ipos = ipos % GRADIENT_STOPTABLE_SIZE;
+ ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
+ } else if (data->spread == QGradient::ReflectSpread) {
+ const int limit = GRADIENT_STOPTABLE_SIZE * 2;
+ ipos = ipos % limit;
+ ipos = ipos < 0 ? limit + ipos : ipos;
+ ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - 1 - ipos : ipos;
+ } else {
+ if (ipos < 0)
+ ipos = 0;
+ else if (ipos >= GRADIENT_STOPTABLE_SIZE)
+ ipos = GRADIENT_STOPTABLE_SIZE-1;
+ }
+ }
+
+ Q_ASSERT(ipos >= 0);
+ Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
+
+ return ipos;
+}
+
+static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos)
+{
+ int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5));
+ return data->colorTable[qt_gradient_clamp(data, ipos)];
+}
+
+static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c)
+{
+ return (b * b) - (4 * a * c);
+}
+
+template <class RadialFetchFunc>
+const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ // avoid division by zero
+ if (qFuzzyIsNull(op->radial.a)) {
+ extern void (*qt_memfill32)(quint32 *dest, quint32 value, int count);
+ qt_memfill32(buffer, 0, length);
+ return buffer;
+ }
+
+ const uint *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;
+ if (affine) {
+ rx -= data->gradient.radial.focal.x;
+ ry -= data->gradient.radial.focal.y;
+
+ qreal inv_a = 1 / qreal(2 * op->radial.a);
+
+ const qreal delta_rx = data->m11;
+ const qreal delta_ry = data->m12;
+
+ qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + rx * op->radial.dx + ry * op->radial.dy);
+ qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy);
+ const qreal b_delta_b = 2 * b * delta_b;
+ const qreal delta_b_delta_b = 2 * delta_b * delta_b;
+
+ const qreal bb = b * b;
+ const qreal delta_bb = delta_b * delta_b;
+
+ b *= inv_a;
+ delta_b *= inv_a;
+
+ const qreal rxrxryry = rx * rx + ry * ry;
+ const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry;
+ const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry);
+ const qreal delta_rx_plus_ry = 2 * delta_rxrxryry;
+
+ inv_a *= inv_a;
+
+ qreal det = (bb - 4 * op->radial.a * (op->radial.sqrfr - rxrxryry)) * inv_a;
+ qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a;
+ const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a;
+
+ RadialFetchFunc::fetch(buffer, end, op, data, det, delta_det, delta_delta_det, b, delta_b);
+ } else {
+ qreal rw = data->m23 * (y + qreal(0.5))
+ + data->m33 + data->m13 * (x + qreal(0.5));
+
+ while (buffer < end) {
+ if (rw == 0) {
+ *buffer = 0;
+ } else {
+ qreal invRw = 1 / rw;
+ qreal gx = rx * invRw - data->gradient.radial.focal.x;
+ qreal gy = ry * invRw - data->gradient.radial.focal.y;
+ 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;
+ if (det >= 0) {
+ qreal detSqrt = qSqrt(det);
+
+ qreal s0 = (-b - detSqrt) * op->radial.inv2a;
+ qreal s1 = (-b + detSqrt) * op->radial.inv2a;
+
+ qreal s = qMax(s0, s1);
+
+ if (data->gradient.radial.focal.radius + op->radial.dr * s >= 0)
+ result = qt_gradient_pixel(&data->gradient, s);
+ }
+
+ *buffer = result;
+ }
+
+ rx += data->m11;
+ ry += data->m12;
+ rw += data->m13;
+
+ ++buffer;
+ }
+ }
+
+ return b;
+}
+
+template <class Simd>
+class QRadialFetchSimd
+{
+public:
+ 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)
+ {
+ typename Simd::Vect_buffer_f det_vec;
+ typename Simd::Vect_buffer_f delta_det4_vec;
+ typename Simd::Vect_buffer_f b_vec;
+
+ for (int i = 0; i < 4; ++i) {
+ det_vec.f[i] = det;
+ delta_det4_vec.f[i] = 4 * delta_det;
+ b_vec.f[i] = b;
+
+ det += delta_det;
+ delta_det += delta_delta_det;
+ b += delta_b;
+ }
+
+ const typename Simd::Float32x4 v_delta_delta_det16 = Simd::v_dup(16 * delta_delta_det);
+ const typename Simd::Float32x4 v_delta_delta_det6 = Simd::v_dup(6 * delta_delta_det);
+ const typename Simd::Float32x4 v_delta_b4 = Simd::v_dup(4 * delta_b);
+
+ const typename Simd::Float32x4 v_r0 = Simd::v_dup(data->gradient.radial.focal.radius);
+ const typename Simd::Float32x4 v_dr = Simd::v_dup(op->radial.dr);
+
+ const typename Simd::Float32x4 v_min = Simd::v_dup(0.0f);
+ const typename Simd::Float32x4 v_max = Simd::v_dup(GRADIENT_STOPTABLE_SIZE-1.5f);
+ const typename Simd::Float32x4 v_half = Simd::v_dup(0.5f);
+
+ const typename Simd::Float32x4 v_table_size_minus_one = Simd::v_dup(float(GRADIENT_STOPTABLE_SIZE-1));
+
+ const typename Simd::Int32x4 v_repeat_mask = Simd::v_dup(~(uint(0xffffff) << GRADIENT_STOPTABLE_SIZE_SHIFT));
+ const typename Simd::Int32x4 v_reflect_mask = Simd::v_dup(~(uint(0xffffff) << (GRADIENT_STOPTABLE_SIZE_SHIFT+1)));
+
+ const typename Simd::Int32x4 v_reflect_limit = Simd::v_dup(2 * GRADIENT_STOPTABLE_SIZE - 1);
+
+ const int extended_mask = op->radial.extended ? 0x0 : ~0x0;
+
+#define FETCH_RADIAL_LOOP_PROLOGUE \
+ while (buffer < end) { \
+ typename Simd::Vect_buffer_i v_buffer_mask; \
+ v_buffer_mask.v = Simd::v_greaterOrEqual(det_vec.v, v_min); \
+ const typename Simd::Float32x4 v_index_local = Simd::v_sub(Simd::v_sqrt(Simd::v_max(v_min, det_vec.v)), b_vec.v); \
+ const typename Simd::Float32x4 v_index = Simd::v_add(Simd::v_mul(v_index_local, v_table_size_minus_one), v_half); \
+ v_buffer_mask.v = Simd::v_and(v_buffer_mask.v, Simd::v_greaterOrEqual(Simd::v_add(v_r0, Simd::v_mul(v_dr, v_index_local)), v_min)); \
+ typename Simd::Vect_buffer_i index_vec;
+#define FETCH_RADIAL_LOOP_CLAMP_REPEAT \
+ index_vec.v = Simd::v_and(v_repeat_mask, Simd::v_toInt(v_index));
+#define FETCH_RADIAL_LOOP_CLAMP_REFLECT \
+ const typename Simd::Int32x4 v_index_i = Simd::v_and(v_reflect_mask, Simd::v_toInt(v_index)); \
+ const typename Simd::Int32x4 v_index_i_inv = Simd::v_sub(v_reflect_limit, v_index_i); \
+ index_vec.v = Simd::v_min_16(v_index_i, v_index_i_inv);
+#define FETCH_RADIAL_LOOP_CLAMP_PAD \
+ index_vec.v = Simd::v_toInt(Simd::v_min(v_max, Simd::v_max(v_min, v_index)));
+#define FETCH_RADIAL_LOOP_EPILOGUE \
+ det_vec.v = Simd::v_add(Simd::v_add(det_vec.v, delta_det4_vec.v), v_delta_delta_det6); \
+ delta_det4_vec.v = Simd::v_add(delta_det4_vec.v, v_delta_delta_det16); \
+ b_vec.v = Simd::v_add(b_vec.v, v_delta_b4); \
+ for (int i = 0; i < 4; ++i) \
+ *buffer++ = (extended_mask | v_buffer_mask.i[i]) & data->gradient.colorTable[index_vec.i[i]]; \
+ }
+
+#define FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP) \
+ FETCH_RADIAL_LOOP_PROLOGUE \
+ FETCH_RADIAL_LOOP_CLAMP \
+ FETCH_RADIAL_LOOP_EPILOGUE
+
+ switch (data->gradient.spread) {
+ case QGradient::RepeatSpread:
+ FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_REPEAT)
+ break;
+ case QGradient::ReflectSpread:
+ FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_REFLECT)
+ break;
+ case QGradient::PadSpread:
+ FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_PAD)
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+ }
+};
+
#if defined(Q_CC_RVCT)
# pragma push
# pragma arm
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index aad6bc9..be6dc91 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -491,6 +491,58 @@ void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y,
}
}
+class QSimdSse2
+{
+public:
+ typedef __m128i Int32x4;
+ typedef __m128 Float32x4;
+
+ union Vect_buffer_i { Int32x4 v; int i[4]; };
+ union Vect_buffer_f { Float32x4 v; float f[4]; };
+
+ static inline Float32x4 v_dup(float x) { return _mm_set1_ps(x); }
+ static inline Float32x4 v_dup(double x) { return _mm_set1_ps(x); }
+ static inline Int32x4 v_dup(int x) { return _mm_set1_epi32(x); }
+ static inline Int32x4 v_dup(uint x) { return _mm_set1_epi32(x); }
+
+ static inline Float32x4 v_add(Float32x4 a, Float32x4 b) { return _mm_add_ps(a, b); }
+ static inline Int32x4 v_add(Int32x4 a, Int32x4 b) { return _mm_add_epi32(a, b); }
+
+ static inline Float32x4 v_max(Float32x4 a, Float32x4 b) { return _mm_max_ps(a, b); }
+ static inline Float32x4 v_min(Float32x4 a, Float32x4 b) { return _mm_min_ps(a, b); }
+ static inline Int32x4 v_min_16(Int32x4 a, Int32x4 b) { return _mm_min_epi16(a, b); }
+
+ static inline Int32x4 v_and(Int32x4 a, Int32x4 b) { return _mm_and_si128(a, b); }
+
+ static inline Float32x4 v_sub(Float32x4 a, Float32x4 b) { return _mm_sub_ps(a, b); }
+ static inline Int32x4 v_sub(Int32x4 a, Int32x4 b) { return _mm_sub_epi32(a, b); }
+
+ static inline Float32x4 v_mul(Float32x4 a, Float32x4 b) { return _mm_mul_ps(a, b); }
+
+ static inline Float32x4 v_sqrt(Float32x4 x) { return _mm_sqrt_ps(x); }
+
+ static inline Int32x4 v_toInt(Float32x4 x) { return _mm_cvttps_epi32(x); }
+
+ // pre-VS 2008 doesn't have cast intrinsics, whereas 2008 and later requires it
+#if defined(Q_CC_MSVC) && _MSC_VER < 1500
+ static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b)
+ {
+ union Convert { Int32x4 vi; Float32x4 vf; } convert;
+ convert.vf = _mm_cmpgt_ps(a, b);
+ return convert.vi;
+ }
+#else
+ static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return _mm_castps_si128(_mm_cmpgt_ps(a, b)); }
+#endif
+};
+
+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);
+}
+
+
QT_END_NAMESPACE
#endif // QT_HAVE_SSE2
diff --git a/src/gui/painting/qpaintengine_mac.cpp b/src/gui/painting/qpaintengine_mac.cpp
index 8aab7c7..cc75b86 100644
--- a/src/gui/painting/qpaintengine_mac.cpp
+++ b/src/gui/painting/qpaintengine_mac.cpp
@@ -1544,8 +1544,9 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
QPointF center(radialGrad->center());
QPointF focal(radialGrad->focalPoint());
qreal radius = radialGrad->radius();
+ qreal focalRadius = radialGrad->focalRadius();
shading = CGShadingCreateRadial(colorspace, CGPointMake(focal.x(), focal.y()),
- 0.0, CGPointMake(center.x(), center.y()), radius, fill_func, false, true);
+ focalRadius, CGPointMake(center.x(), center.y()), radius, fill_func, false, true);
}
CGFunctionRelease(fill_func);
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 6902543..2119e30 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -5033,6 +5033,84 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
+ if (stopCount == 2) {
+ uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
+ uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
+
+ qreal first_stop = stops[0].first;
+ qreal second_stop = stops[1].first;
+
+ if (second_stop < first_stop) {
+ qSwap(first_color, second_color);
+ qSwap(first_stop, second_stop);
+ }
+
+ if (colorInterpolation) {
+ first_color = PREMUL(first_color);
+ second_color = PREMUL(second_color);
+ }
+
+ int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
+ int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
+
+ uint red_first = qRed(first_color) << 16;
+ uint green_first = qGreen(first_color) << 16;
+ uint blue_first = qBlue(first_color) << 16;
+ uint alpha_first = qAlpha(first_color) << 16;
+
+ uint red_second = qRed(second_color) << 16;
+ uint green_second = qGreen(second_color) << 16;
+ uint blue_second = qBlue(second_color) << 16;
+ uint alpha_second = qAlpha(second_color) << 16;
+
+ int i = 0;
+ for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
+ if (colorInterpolation)
+ colorTable[i] = first_color;
+ else
+ colorTable[i] = PREMUL(first_color);
+ }
+
+ if (i < second_index) {
+ qreal reciprocal = qreal(1) / (second_index - first_index);
+
+ int red_delta = qRound(int(red_second - red_first) * reciprocal);
+ int green_delta = qRound(int(green_second - green_first) * reciprocal);
+ int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
+ int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
+
+ // rounding
+ red_first += 1 << 15;
+ green_first += 1 << 15;
+ blue_first += 1 << 15;
+ alpha_first += 1 << 15;
+
+ for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
+ red_first += red_delta;
+ green_first += green_delta;
+ blue_first += blue_delta;
+ alpha_first += alpha_delta;
+
+ const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
+ | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
+
+ if (colorInterpolation)
+ colorTable[i] = color;
+ else
+ colorTable[i] = PREMUL(color);
+ }
+ }
+
+ for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
+ if (colorInterpolation)
+ colorTable[i] = second_color;
+ else
+ colorTable[i] = PREMUL(second_color);
+ }
+
+ return;
+ }
+
uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
if (stopCount == 1) {
current_color = PREMUL(current_color);
@@ -5204,10 +5282,11 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
QPointF center = g->center();
radialData.center.x = center.x();
radialData.center.y = center.y();
+ radialData.center.radius = g->centerRadius();
QPointF focal = g->focalPoint();
radialData.focal.x = focal.x();
radialData.focal.y = focal.y();
- radialData.radius = g->radius();
+ radialData.focal.radius = g->focalRadius();
}
break;
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 509fb77..7f601eb 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -1012,4 +1012,50 @@ void QPaintEngineEx::updateState(const QPaintEngineState &)
// do nothing...
}
+Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path)
+{
+ const qreal *points = path.points();
+ const QPainterPath::ElementType *types = path.elements();
+
+ QPainterPath p;
+ if (types) {
+ int id = 0;
+ for (int i=0; i<path.elementCount(); ++i) {
+ switch(types[i]) {
+ case QPainterPath::MoveToElement:
+ p.moveTo(QPointF(points[id], points[id+1]));
+ id+=2;
+ break;
+ case QPainterPath::LineToElement:
+ p.lineTo(QPointF(points[id], points[id+1]));
+ id+=2;
+ break;
+ case QPainterPath::CurveToElement: {
+ QPointF p1(points[id], points[id+1]);
+ QPointF p2(points[id+2], points[id+3]);
+ QPointF p3(points[id+4], points[id+5]);
+ p.cubicTo(p1, p2, p3);
+ id+=6;
+ break;
+ }
+ case QPainterPath::CurveToDataElement:
+ ;
+ break;
+ }
+ }
+ } else {
+ p.moveTo(QPointF(points[0], points[1]));
+ int id = 2;
+ for (int i=1; i<path.elementCount(); ++i) {
+ p.lineTo(QPointF(points[id], points[id+1]));
+ id+=2;
+ }
+ }
+ if (path.hints() & QVectorPath::WindingFill)
+ p.setFillRule(Qt::WindingFill);
+
+ return p;
+}
+
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 9fafba5..9e28102 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -156,7 +156,8 @@ static bool qt_paintengine_supports_transformations(QPaintEngine::Type type)
{
return type == QPaintEngine::OpenGL2
|| type == QPaintEngine::OpenVG
- || type == QPaintEngine::OpenGL;
+ || type == QPaintEngine::OpenGL
+ || type == QPaintEngine::CoreGraphics;
}
#ifndef QT_NO_DEBUG
@@ -503,8 +504,12 @@ void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperatio
q->save();
state->matrix = QTransform();
- state->dirtyFlags |= QPaintEngine::DirtyTransform;
- updateState(state);
+ if (extended) {
+ extended->transformChanged();
+ } else {
+ state->dirtyFlags |= QPaintEngine::DirtyTransform;
+ updateState(state);
+ }
engine->drawImage(absPathRect,
image,
QRectF(0, 0, absPathRect.width(), absPathRect.height()),
@@ -687,11 +692,14 @@ void QPainterPrivate::updateInvMatrix()
invMatrix = state->matrix.inverted();
}
+extern bool qt_isExtendedRadialGradient(const QBrush &brush);
+
void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
{
bool alpha = false;
bool linearGradient = false;
bool radialGradient = false;
+ bool extendedRadialGradient = false;
bool conicalGradient = false;
bool patternBrush = false;
bool xform = false;
@@ -723,6 +731,7 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
(brushStyle == Qt::LinearGradientPattern));
radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) ||
(brushStyle == Qt::RadialGradientPattern));
+ extendedRadialGradient = radialGradient && (qt_isExtendedRadialGradient(penBrush) || qt_isExtendedRadialGradient(s->brush));
conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) ||
(brushStyle == Qt::ConicalGradientPattern));
patternBrush = (((penBrushStyle > Qt::SolidPattern
@@ -806,7 +815,7 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill;
// Radial gradient emulation
- if (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill))
+ if (extendedRadialGradient || (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill)))
s->emulationSpecifier |= QPaintEngine::RadialGradientFill;
else
s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill;
@@ -5809,7 +5818,7 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs)
bool paintEngineSupportsTransformations =
d->extended != 0
? qt_paintengine_supports_transformations(d->extended->type())
- : false;
+ : qt_paintengine_supports_transformations(d->engine->type());
for (int i=0; i<count; ++i) {
QPointF processedPosition = position + glyphPositions.at(i);
if (!paintEngineSupportsTransformations)
diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h
index 4b2c447..1a432e6 100644
--- a/src/gui/painting/qpainter.h
+++ b/src/gui/painting/qpainter.h
@@ -553,6 +553,7 @@ private:
friend class QPaintEngine;
friend class QPaintEngineExPrivate;
friend class QOpenGLPaintEngine;
+ friend class QVGPaintEngine;
friend class QX11PaintEngine;
friend class QX11PaintEnginePrivate;
friend class QWin32PaintEngine;
diff --git a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
index 3876c3d..2fda6b9 100644
--- a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
+++ b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
@@ -152,7 +152,8 @@ void QUnifiedToolbarSurface::beginPaint(const QRegion &rgn)
void QUnifiedToolbarSurface::updateToolbarOffset(QWidget *widget)
{
QMainWindowLayout *mlayout = qobject_cast<QMainWindowLayout*> (widget->window()->layout());
- mlayout->updateUnifiedToolbarOffset();
+ if (mlayout)
+ mlayout->updateUnifiedToolbarOffset();
}
void QUnifiedToolbarSurface::flush(QWidget *widget, const QRegion &region, const QPoint &offset)