Added support for six-parameter radial gradients.

The extended radial gradients conform to the radial gradient
specification in HTML 5 canvas.

Task-number: QTBUG-14075
Reviewed-by: Andreas Kling
(cherry picked from commit da55c1ea92474e989e5582b02815936bbf584405)
This commit is contained in:
Samuel Rødal 2011-04-13 10:16:43 +02:00 committed by Olivier Goffart
parent ad295e7402
commit 83ecb25998
21 changed files with 618 additions and 131 deletions

View File

@ -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

View File

@ -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);
};

View File

@ -1406,23 +1406,47 @@ static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const Q
{
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;
v->dr = data->gradient.radial.center.radius - data->gradient.radial.focal.radius;
v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius;
v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy;
v->inv2a = 1 / (2 * v->a);
v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0;
}
class RadialFetchPlain
{
public:
static inline void fetch(uint *buffer, uint *end, const QSpanData *data, qreal det, qreal delta_det,
qreal delta_delta_det, qreal b, qreal delta_b)
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)
{
while (buffer < end) {
*buffer = qt_gradient_pixel(&data->gradient, (det > 0 ? qSqrt(det) : 0) - 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);
}
det += delta_det;
delta_det += delta_delta_det;
b += delta_b;
*buffer = result;
++buffer;
det += delta_det;
delta_det += delta_delta_det;
b += delta_b;
++buffer;
}
} else {
while (buffer < end) {
*buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b);
det += delta_det;
delta_det += delta_delta_det;
b += delta_b;
}
}
}
};

View File

@ -985,6 +985,8 @@ public:
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,

View File

@ -191,7 +191,11 @@ struct RadialGradientValues
{
qreal dx;
qreal dy;
qreal dr;
qreal sqrfr;
qreal a;
qreal inv2a;
bool extended;
};
struct Operator;
@ -239,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
@ -381,12 +386,6 @@ static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c)
return (b * b) - (4 * a * c);
}
// function to evaluate real roots
static inline qreal qRadialRealRoots(qreal a, qreal b, qreal detSqrt)
{
return (-b + detSqrt)/(2 * a);
}
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)
@ -394,7 +393,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O
// avoid division by zero
if (qFuzzyIsNull(op->radial.a)) {
extern void (*qt_memfill32)(quint32 *dest, quint32 value, int count);
qt_memfill32(buffer, data->gradient.colorTable[0], length);
qt_memfill32(buffer, 0, length);
return buffer;
}
@ -415,7 +414,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O
const qreal delta_rx = data->m11;
const qreal delta_ry = data->m12;
qreal b = 2*(rx * op->radial.dx + ry * op->radial.dy);
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;
@ -433,31 +432,45 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O
inv_a *= inv_a;
qreal det = (bb + 4 * op->radial.a * rxrxryry) * 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, data, det, delta_det, delta_delta_det, b, delta_b);
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));
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 = qRadialDeterminant(op->radial.a, b , -(gx*gx + gy*gy));
qreal s = qRadialRealRoots(op->radial.a, b, (det > 0 ? qSqrt(det) : 0));
*buffer = qt_gradient_pixel(&data->gradient, s);
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;
if (!rw) {
rw += data->m13;
}
++buffer;
}
}
@ -469,8 +482,8 @@ template <class Simd>
class QRadialFetchSimd
{
public:
static inline void fetch(uint *buffer, uint *end, const QSpanData *data, qreal det, qreal delta_det,
qreal delta_delta_det, qreal b, qreal delta_b)
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;
@ -490,6 +503,9 @@ public:
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);
@ -501,10 +517,15 @@ public:
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));
@ -519,21 +540,26 @@ public:
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++ = data->gradient.colorTable[index_vec.i[i]]; \
*buffer++ = (extended_mask | v_buffer_mask.i[i]) & data->gradient.colorTable[index_vec.i[i]]; \
}
if (data->gradient.spread == QGradient::RepeatSpread) {
FETCH_RADIAL_LOOP_PROLOGUE
FETCH_RADIAL_LOOP_CLAMP_REPEAT
FETCH_RADIAL_LOOP_EPILOGUE
} else if (data->gradient.spread == QGradient::ReflectSpread) {
FETCH_RADIAL_LOOP_PROLOGUE
FETCH_RADIAL_LOOP_CLAMP_REFLECT
FETCH_RADIAL_LOOP_EPILOGUE
} else {
FETCH_RADIAL_LOOP_PROLOGUE
FETCH_RADIAL_LOOP_CLAMP_PAD
FETCH_RADIAL_LOOP_EPILOGUE
#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);
}
}
};

View File

@ -522,6 +522,8 @@ public:
static inline Float32x4 v_sqrt(Float32x4 x) { return _mm_sqrt_ps(x); }
static inline Int32x4 v_toInt(Float32x4 x) { return _mm_cvttps_epi32(x); }
static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return (__m128i)_mm_cmpgt_ps(a, b); }
};
const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,

View File

@ -1546,8 +1546,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);

View File

@ -5282,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;

View File

@ -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

View File

@ -504,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()),
@ -688,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;
@ -724,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
@ -807,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;

View File

@ -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;

View File

@ -495,6 +495,8 @@ GLuint QGLEngineShaderManager::getUniformLocation(Uniform id)
"fmp",
"fmp2_m_radius2",
"inverse_2_fmp2_m_radius2",
"sqrfr",
"bradius",
"invertedTextureSize",
"brushTransform",
"brushTexture",

View File

@ -442,6 +442,8 @@ public:
Fmp,
Fmp2MRadius2,
Inverse2Fmp2MRadius2,
SqrFr,
BRadius,
InvertedTextureSize,
BrushTransform,
BrushTexture,

View File

@ -241,6 +241,7 @@ static const char* const qglslPositionWithRadialGradientBrushVertexShader = "\n\
uniform mediump vec2 halfViewportSize; \n\
uniform highp mat3 brushTransform; \n\
uniform highp vec2 fmp; \n\
uniform highp vec3 bradius; \n\
varying highp float b; \n\
varying highp vec2 A; \n\
void setPosition(void) \n\
@ -253,7 +254,7 @@ static const char* const qglslPositionWithRadialGradientBrushVertexShader = "\n\
mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
A = hTexCoords.xy * invertedHTexCoordsZ; \n\
b = 2.0 * dot(A, fmp); \n\
b = bradius.x + 2.0 * dot(A, fmp); \n\
}\n";
static const char* const qglslAffinePositionWithRadialGradientBrushVertexShader
@ -263,13 +264,22 @@ static const char* const qglslRadialGradientBrushSrcFragmentShader = "\n\
uniform sampler2D brushTexture; \n\
uniform highp float fmp2_m_radius2; \n\
uniform highp float inverse_2_fmp2_m_radius2; \n\
uniform highp float sqrfr; \n\
varying highp float b; \n\
varying highp vec2 A; \n\
uniform highp vec3 bradius; \n\
lowp vec4 srcPixel() \n\
{ \n\
highp float c = -dot(A, A); \n\
highp vec2 val = vec2((-b + sqrt(b*b - 4.0*fmp2_m_radius2*c)) * inverse_2_fmp2_m_radius2, 0.5); \n\
return texture2D(brushTexture, val); \n\
highp float c = sqrfr-dot(A, A); \n\
highp float det = b*b - 4.0*fmp2_m_radius2*c; \n\
lowp vec4 result = vec4(0.0); \n\
if (det >= 0.0) { \n\
highp float detSqrt = sqrt(det); \n\
highp float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); \n\
if (bradius.y + w * bradius.z >= 0.0) \n\
result = texture2D(brushTexture, vec2(w, 0.5)); \n\
} \n\
return result; \n\
}\n";

View File

@ -301,7 +301,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush.gradient());
QPointF realCenter = g->center();
QPointF realFocal = g->focalPoint();
qreal realRadius = g->radius();
qreal realRadius = g->centerRadius() - g->focalRadius();
translationPoint = realFocal;
QPointF fmp = realCenter - realFocal;
@ -311,6 +311,12 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Fmp2MRadius2), fmp2_m_radius2);
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Inverse2Fmp2MRadius2),
GLfloat(1.0 / (2.0*fmp2_m_radius2)));
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::SqrFr),
GLfloat(g->focalRadius() * g->focalRadius()));
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BRadius),
GLfloat(2 * (g->centerRadius() - g->focalRadius()) * g->focalRadius()),
g->focalRadius(),
g->centerRadius() - g->focalRadius());
QVector2D halfViewportSize(width*0.5, height*0.5);
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);

View File

@ -2119,6 +2119,7 @@ void QOpenGLPaintEnginePrivate::fillPath(const QPainterPath &path)
updateGLMatrix();
}
extern bool qt_isExtendedRadialGradient(const QBrush &brush);
static inline bool needsEmulation(Qt::BrushStyle style)
{
@ -2129,9 +2130,11 @@ static inline bool needsEmulation(Qt::BrushStyle style)
void QOpenGLPaintEnginePrivate::updateUseEmulation()
{
use_emulation = !use_fragment_programs
&& ((has_pen && needsEmulation(pen_brush_style))
|| (has_brush && needsEmulation(brush_style)));
use_emulation = (!use_fragment_programs
&& ((has_pen && needsEmulation(pen_brush_style))
|| (has_brush && needsEmulation(brush_style))))
|| (has_pen && qt_isExtendedRadialGradient(cpen.brush()))
|| (has_brush && qt_isExtendedRadialGradient(cbrush));
}
void QOpenGLPaintEngine::updatePen(const QPen &pen)
@ -5447,50 +5450,7 @@ void QOpenGLPaintEngine::transformChanged()
updateMatrix(state()->matrix);
}
static QPainterPath 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;
}
extern QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path);
void QOpenGLPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
{
@ -5499,11 +5459,11 @@ void QOpenGLPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
if (brush.style() == Qt::NoBrush)
return;
if (!d->use_fragment_programs && needsEmulation(brush.style())) {
if ((!d->use_fragment_programs && needsEmulation(brush.style())) || qt_isExtendedRadialGradient(brush)) {
QPainter *p = painter();
QBrush oldBrush = p->brush();
p->setBrush(brush);
qt_draw_helper(p->d_ptr.data(), painterPathFromVectorPath(path), QPainterPrivate::FillDraw);
qt_draw_helper(p->d_ptr.data(), qt_painterPathFromVectorPath(path), QPainterPrivate::FillDraw);
p->setBrush(oldBrush);
return;
}
@ -5520,7 +5480,7 @@ void QOpenGLPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
drawRects(&r, 1);
updatePen(old_pen);
} else {
d->fillPath(painterPathFromVectorPath(path));
d->fillPath(qt_painterPathFromVectorPath(path));
}
updateBrush(old_brush, state()->brushOrigin);

View File

@ -173,6 +173,9 @@ public:
bool forcePenChange; // Force a pen change, even if the same.
bool forceBrushChange; // Force a brush change, even if the same.
bool hasExtendedRadialGradientPen; // Current pen's brush is extended radial gradient.
bool hasExtendedRadialGradientBrush; // Current brush is extended radial gradient.
VGPaintType penType; // Type of the last pen that was set.
VGPaintType brushType; // Type of the last brush that was set.
@ -275,6 +278,27 @@ public:
}
}
inline bool needsEmulation(const QBrush &brush) const
{
extern bool qt_isExtendedRadialGradient(const QBrush &brush);
return qt_isExtendedRadialGradient(brush);
}
inline bool needsEmulation() const
{
return hasExtendedRadialGradientPen || hasExtendedRadialGradientBrush;
}
inline bool needsPenEmulation() const
{
return hasExtendedRadialGradientPen;
}
inline bool needsBrushEmulation() const
{
return hasExtendedRadialGradientBrush;
}
// Set various modes, but only if different.
inline void setImageMode(VGImageMode mode);
inline void setRenderingQuality(VGRenderingQuality mode);
@ -355,6 +379,10 @@ void QVGPaintEnginePrivate::init()
forcePenChange = true;
forceBrushChange = true;
hasExtendedRadialGradientPen = false;
hasExtendedRadialGradientBrush = false;
penType = (VGPaintType)0;
brushType = (VGPaintType)0;
@ -1536,6 +1564,10 @@ bool QVGPaintEngine::end()
void QVGPaintEngine::draw(const QVectorPath &path)
{
Q_D(QVGPaintEngine);
if (d->needsEmulation()) {
QPaintEngineEx::draw(path);
return;
}
QVGPainterState *s = state();
VGPath vgpath = d->vectorPathToVGPath(path);
if (!path.hasWindingFill())
@ -1545,9 +1577,19 @@ void QVGPaintEngine::draw(const QVectorPath &path)
vgDestroyPath(vgpath);
}
extern QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path);
void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
{
Q_D(QVGPaintEngine);
if (d->needsEmulation(brush)) {
QPainter *p = painter();
QBrush oldBrush = p->brush();
p->setBrush(brush);
qt_draw_helper(p->d_ptr.data(), qt_painterPathFromVectorPath(path), QPainterPrivate::FillDraw);
p->setBrush(oldBrush);
return;
}
VGPath vgpath = d->vectorPathToVGPath(path);
if (!path.hasWindingFill())
d->fill(vgpath, brush, VG_EVEN_ODD);
@ -1559,6 +1601,10 @@ void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
void QVGPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
{
Q_D(QVGPaintEngine);
if (d->needsEmulation(pen.brush())) {
QPaintEngineEx::stroke(path, pen);
return;
}
VGPath vgpath = d->vectorPathToVGPath(path);
d->stroke(vgpath, pen);
vgDestroyPath(vgpath);
@ -2362,12 +2408,17 @@ void QVGPaintEngine::penChanged()
{
Q_D(QVGPaintEngine);
d->dirty |= QPaintEngine::DirtyPen;
d->hasExtendedRadialGradientPen =
state()->pen.style() != Qt::NoPen && d->needsEmulation(state()->pen.brush());
}
void QVGPaintEngine::brushChanged()
{
Q_D(QVGPaintEngine);
d->dirty |= QPaintEngine::DirtyBrush;
d->hasExtendedRadialGradientPen = d->needsEmulation(state()->brush);
}
void QVGPaintEngine::brushOriginChanged()
@ -2546,6 +2597,11 @@ void QVGPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
return;
}
if (d->needsEmulation(brush)) {
QPaintEngineEx::fillRect(rect, brush);
return;
}
#if !defined(QVG_NO_MODIFY_PATH)
VGfloat coords[8];
if (d->simpleTransform) {
@ -2623,6 +2679,10 @@ void QVGPaintEngine::fillRect(const QRectF &rect, const QColor &color)
void QVGPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode)
{
Q_D(QVGPaintEngine);
if (d->needsEmulation()) {
QPaintEngineEx::drawRoundedRect(rect, xrad, yrad, mode);
return;
}
if (d->simpleTransform) {
QVGPainterState *s = state();
VGPath vgpath = d->roundedRectPath(rect, xrad, yrad, mode);
@ -2639,6 +2699,10 @@ void QVGPaintEngine::drawRects(const QRect *rects, int rectCount)
{
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
if (d->needsEmulation()) {
QPaintEngineEx::drawRects(rects, rectCount);
return;
}
QVGPainterState *s = state();
for (int i = 0; i < rectCount; ++i, ++rects) {
VGfloat coords[8];
@ -2680,6 +2744,10 @@ void QVGPaintEngine::drawRects(const QRectF *rects, int rectCount)
{
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
if (d->needsEmulation()) {
QPaintEngineEx::drawRects(rects, rectCount);
return;
}
QVGPainterState *s = state();
for (int i = 0; i < rectCount; ++i, ++rects) {
VGfloat coords[8];
@ -2718,6 +2786,10 @@ void QVGPaintEngine::drawLines(const QLine *lines, int lineCount)
{
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
if (d->needsEmulation()) {
QPaintEngineEx::drawLines(lines, lineCount);
return;
}
QVGPainterState *s = state();
for (int i = 0; i < lineCount; ++i, ++lines) {
VGfloat coords[4];
@ -2746,6 +2818,10 @@ void QVGPaintEngine::drawLines(const QLineF *lines, int lineCount)
{
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
if (d->needsEmulation()) {
QPaintEngineEx::drawLines(lines, lineCount);
return;
}
QVGPainterState *s = state();
for (int i = 0; i < lineCount; ++i, ++lines) {
VGfloat coords[4];
@ -2775,6 +2851,10 @@ void QVGPaintEngine::drawEllipse(const QRectF &r)
// Based on the description of vguEllipse() in the OpenVG specification.
// We don't use vguEllipse(), to avoid unnecessary library dependencies.
Q_D(QVGPaintEngine);
if (d->needsEmulation()) {
QPaintEngineEx::drawEllipse(r);
return;
}
if (d->simpleTransform) {
QVGPainterState *s = state();
VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
@ -2825,6 +2905,10 @@ void QVGPaintEngine::drawPath(const QPainterPath &path)
// Shortcut past the QPainterPath -> QVectorPath conversion,
// converting the QPainterPath directly into a VGPath.
Q_D(QVGPaintEngine);
if (d->needsEmulation()) {
QPaintEngineEx::drawPath(path);
return;
}
QVGPainterState *s = state();
VGPath vgpath = d->painterPathToVGPath(path);
if (path.fillRule() == Qt::OddEvenFill)
@ -2839,6 +2923,11 @@ void QVGPaintEngine::drawPoints(const QPointF *points, int pointCount)
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
if (d->needsPenEmulation()) {
QPaintEngineEx::drawPoints(points, pointCount);
return;
}
// Set up a new pen if necessary.
QPen pen = state()->pen;
if (pen.style() == Qt::NoPen)
@ -2873,6 +2962,11 @@ void QVGPaintEngine::drawPoints(const QPoint *points, int pointCount)
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
if (d->needsEmulation()) {
QPaintEngineEx::drawPoints(points, pointCount);
return;
}
// Set up a new pen if necessary.
QPen pen = state()->pen;
if (pen.style() == Qt::NoPen)
@ -2905,6 +2999,12 @@ void QVGPaintEngine::drawPoints(const QPoint *points, int pointCount)
void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
{
Q_D(QVGPaintEngine);
if (d->needsEmulation()) {
QPaintEngineEx::drawPolygon(points, pointCount, mode);
return;
}
QVGPainterState *s = state();
VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
VG_PATH_DATATYPE_F,
@ -2952,6 +3052,12 @@ void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonD
void QVGPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
{
Q_D(QVGPaintEngine);
if (d->needsEmulation()) {
QPaintEngineEx::drawPolygon(points, pointCount, mode);
return;
}
QVGPainterState *s = state();
VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
VG_PATH_DATATYPE_F,
@ -3611,6 +3717,11 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
return;
}
if (d->needsPenEmulation()) {
QPaintEngineEx::drawTextItem(p, textItem);
return;
}
// Get the glyphs and positions associated with the text item.
QVarLengthArray<QFixedPoint> positions;
QVarLengthArray<glyph_t> glyphs;

View File

@ -346,8 +346,12 @@ void PaintCommands::staticInit()
"gradient_setLinear 1.0 1.0 2.0 2.0");
DECL_PAINTCOMMAND("gradient_setRadial", command_gradient_setRadial,
"^gradient_setRadial\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)$",
"gradient_setRadial <cx> <cy> <rad> <fx> <fy>\n - C is the center\n - rad is the angle in degrees\n - F is the focal point",
"gradient_setRadial <cx> <cy> <rad> <fx> <fy>\n - C is the center\n - rad is the radius\n - F is the focal point",
"gradient_setRadial 1.0 1.0 45.0 2.0 2.0");
DECL_PAINTCOMMAND("gradient_setRadialExtended", command_gradient_setRadialExtended,
"^gradient_setRadialExtended\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)$",
"gradient_setRadialExtended <cx> <cy> <rad> <fx> <fy> <frad>\n - C is the center\n - rad is the center radius\n - F is the focal point\n - frad is the focal radius",
"gradient_setRadialExtended 1.0 1.0 45.0 2.0 2.0 45.0");
DECL_PAINTCOMMAND("gradient_setLinearPen", command_gradient_setLinearPen,
"^gradient_setLinearPen\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)$",
"gradient_setLinearPen <x1> <y1> <x2> <y2>",
@ -2400,7 +2404,7 @@ void PaintCommands::command_gradient_setRadial(QRegExp re)
double fy = convertToDouble(caps.at(5));
if (m_verboseMode)
printf(" -(lance) gradient_setRadial center=(%.2f, %.2f), radius=%.2f focal=(%.2f, %.2f), "
printf(" -(lance) gradient_setRadial center=(%.2f, %.2f), radius=%.2f, focal=(%.2f, %.2f), "
"spread=%d\n",
cx, cy, rad, fx, fy, m_gradientSpread);
@ -2414,6 +2418,32 @@ void PaintCommands::command_gradient_setRadial(QRegExp re)
m_painter->setBrush(brush);
}
/***************************************************************************************************/
void PaintCommands::command_gradient_setRadialExtended(QRegExp re)
{
QStringList caps = re.capturedTexts();
double cx = convertToDouble(caps.at(1));
double cy = convertToDouble(caps.at(2));
double rad = convertToDouble(caps.at(3));
double fx = convertToDouble(caps.at(4));
double fy = convertToDouble(caps.at(5));
double frad = convertToDouble(caps.at(6));
if (m_verboseMode)
printf(" -(lance) gradient_setRadialExtended center=(%.2f, %.2f), radius=%.2f, focal=(%.2f, %.2f), "
"focal radius=%.2f, spread=%d\n",
cx, cy, rad, fx, fy, frad, m_gradientSpread);
QRadialGradient rg(QPointF(cx, cy), rad, QPointF(fx, fy), frad);
rg.setStops(m_gradientStops);
rg.setSpread(m_gradientSpread);
rg.setCoordinateMode(m_gradientCoordinate);
QBrush brush(rg);
QTransform brush_matrix = m_painter->brush().transform();
brush.setTransform(brush_matrix);
m_painter->setBrush(brush);
}
/***************************************************************************************************/
void PaintCommands::command_gradient_setConical(QRegExp re)
{

View File

@ -179,6 +179,7 @@ private:
void command_gradient_setConical(QRegExp re);
void command_gradient_setLinear(QRegExp re);
void command_gradient_setRadial(QRegExp re);
void command_gradient_setRadialExtended(QRegExp re);
void command_gradient_setLinearPen(QRegExp re);
void command_gradient_setSpread(QRegExp re);
void command_gradient_setCoordinateMode(QRegExp re);

View File

@ -0,0 +1,95 @@
path_addRect path 400 0 80 80
path_addEllipse path 440 40 60 60
setRenderHint Antialiasing
setPen black
begin_block gradients
gradient_clearStops
gradient_appendStop 0 red
gradient_appendStop 0.25 orange
gradient_appendStop 0.5 yellow
gradient_appendStop 0.8 green
gradient_appendStop 1 cyan
gradient_setSpread PadSpread
gradient_setRadialExtended 0 0 20 40 40 10
drawRect 0 0 100 100
gradient_setSpread ReflectSpread
gradient_setRadialExtended 120 20 20 140 40 10
drawEllipse 100 0 100 100
gradient_setSpread RepeatSpread
gradient_setRadialExtended 240 20 20 260 40 10
drawRoundRect 200 0 100 100
gradient_clearStops
gradient_appendStop 0 3f7f7fff
gradient_appendStop 0.5 dfdfffff
gradient_appendStop 1 7f00007f
gradient_setSpread PadSpread
gradient_setRadialExtended 320 20 20 340 40 10
drawPolygon [300 0 390 0 350 99]
gradient_setSpread ReflectSpread
gradient_setRadialExtended 420 20 20 440 40 10
drawPath path
gradient_setSpread RepeatSpread
gradient_setRadialExtended 520 20 20 540 40 10
drawPie 500 0 100 100 720 4320
end_block
translate 0 100
scale 1 2
repeat_block gradients
resetMatrix
translate 0 300
brushTranslate 30 0
brushScale 0.9 0.9
repeat_block gradients
# Some helpful info perhaps?
resetMatrix
setPen black
drawText 610 50 "No XForm"
drawText 610 200 "scale 1x2"
drawText 610 300 "brush transform"
drawText 10 450 "Pad"
drawText 110 450 "Reflect"
drawText 210 450 "Repeat"
drawText 310 450 "Pad w/alpha"
drawText 410 450 "Reflect w/alpha"
drawText 510 450 "Repeat w/alpha"
# Radius and focal indicators
setPen 3f000000
setBrush nobrush
begin_block ellipse_draw
setClipRect 0 0 100 100
drawEllipse -30 -30 100 100
drawEllipse 35 35 11 11
translate 100 0
end_block
repeat_block ellipse_draw
repeat_block ellipse_draw
repeat_block ellipse_draw
repeat_block ellipse_draw
repeat_block ellipse_draw
resetMatrix
translate 0 100
scale 1 2
repeat_block ellipse_draw
repeat_block ellipse_draw
repeat_block ellipse_draw
repeat_block ellipse_draw
repeat_block ellipse_draw
repeat_block ellipse_draw

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB