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:
parent
ad295e7402
commit
83ecb25998
@ -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 ¢er,
|
||||
}
|
||||
|
||||
/*!
|
||||
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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er, 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 ¢er)
|
||||
/*!
|
||||
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
|
||||
|
@ -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 ¢er, qreal radius);
|
||||
QRadialGradient(qreal cx, qreal cy, qreal radius);
|
||||
|
||||
QRadialGradient(const QPointF ¢er, 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 ¢er);
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -495,6 +495,8 @@ GLuint QGLEngineShaderManager::getUniformLocation(Uniform id)
|
||||
"fmp",
|
||||
"fmp2_m_radius2",
|
||||
"inverse_2_fmp2_m_radius2",
|
||||
"sqrfr",
|
||||
"bradius",
|
||||
"invertedTextureSize",
|
||||
"brushTransform",
|
||||
"brushTexture",
|
||||
|
@ -442,6 +442,8 @@ public:
|
||||
Fmp,
|
||||
Fmp2MRadius2,
|
||||
Inverse2Fmp2MRadius2,
|
||||
SqrFr,
|
||||
BRadius,
|
||||
InvertedTextureSize,
|
||||
BrushTransform,
|
||||
BrushTexture,
|
||||
|
@ -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";
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
95
tests/arthur/data/qps/radial_gradients_extended.qps
Normal file
95
tests/arthur/data/qps/radial_gradients_extended.qps
Normal 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
|
BIN
tests/arthur/data/qps/radial_gradients_extended_qps.png
Normal file
BIN
tests/arthur/data/qps/radial_gradients_extended_qps.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 105 KiB |
Loading…
Reference in New Issue
Block a user