1049
1068
gstop.offset = 0.0;
1050
1069
gstop.color.set( 0x00000000 );
1051
1070
gstop.opacity = 0.0;
1052
gr->vector.stops.push_back(gstop);
1071
vector.stops.push_back(gstop);
1055
1074
SPGradientStop gstop;
1056
1075
gstop.offset = 1.0;
1057
1076
gstop.color.set( 0x00000000 );
1058
1077
gstop.opacity = 0.0;
1059
gr->vector.stops.push_back(gstop);
1078
vector.stops.push_back(gstop);
1062
1081
/* "If one stop is defined, then paint with the solid color fill using the color defined
1063
1082
* for that gradient stop."
1065
if (gr->vector.stops.front().offset > 0.0) {
1084
if (vector.stops.front().offset > 0.0) {
1066
1085
// If the first one is not at 0, then insert a copy of the first at 0.
1067
1086
SPGradientStop gstop;
1068
1087
gstop.offset = 0.0;
1069
gstop.color = gr->vector.stops.front().color;
1070
gstop.opacity = gr->vector.stops.front().opacity;
1071
gr->vector.stops.insert(gr->vector.stops.begin(), gstop);
1088
gstop.color = vector.stops.front().color;
1089
gstop.opacity = vector.stops.front().opacity;
1090
vector.stops.insert(vector.stops.begin(), gstop);
1073
if (gr->vector.stops.back().offset < 1.0) {
1092
if (vector.stops.back().offset < 1.0) {
1074
1093
// If the last one is not at 1, then insert a copy of the last at 1.
1075
1094
SPGradientStop gstop;
1076
1095
gstop.offset = 1.0;
1077
gstop.color = gr->vector.stops.back().color;
1078
gstop.opacity = gr->vector.stops.back().opacity;
1079
gr->vector.stops.push_back(gstop);
1083
gr->vector.built = true;
1087
* The gradient's color array is newly created and set up from vector.
1090
sp_gradient_ensure_colors(SPGradient *gr)
1092
if (!gr->vector.built) {
1093
sp_gradient_rebuild_vector(gr);
1095
g_return_if_fail(!gr->vector.stops.empty());
1097
/// \todo Where is the memory freed?
1099
gr->color = g_new(guchar, 4 * NCOLORS);
1102
// This assumes that gr->vector is a zero-order B-spline (box function) approximation of the "true" gradient.
1103
// This means that the "true" gradient must be prefiltered using a zero order B-spline and then sampled.
1104
// Furthermore, the first element corresponds to offset="0" and the last element to offset="1".
1106
double remainder[4] = {0,0,0,0};
1107
double remainder_for_end[4] = {0,0,0,0}; // Used at the end
1108
switch(gr->spread) {
1109
case SP_GRADIENT_SPREAD_PAD:
1110
remainder[0] = 0.5*gr->vector.stops[0].color.v.c[0]; // Half of the first cell uses the color of the first stop
1111
remainder[1] = 0.5*gr->vector.stops[0].color.v.c[1];
1112
remainder[2] = 0.5*gr->vector.stops[0].color.v.c[2];
1113
remainder[3] = 0.5*gr->vector.stops[0].opacity;
1114
remainder_for_end[0] = 0.5*gr->vector.stops[gr->vector.stops.size() - 1].color.v.c[0]; // Half of the first cell uses the color of the last stop
1115
remainder_for_end[1] = 0.5*gr->vector.stops[gr->vector.stops.size() - 1].color.v.c[1];
1116
remainder_for_end[2] = 0.5*gr->vector.stops[gr->vector.stops.size() - 1].color.v.c[2];
1117
remainder_for_end[3] = 0.5*gr->vector.stops[gr->vector.stops.size() - 1].opacity;
1119
case SP_GRADIENT_SPREAD_REFLECT:
1120
case SP_GRADIENT_SPREAD_REPEAT:
1121
// These two are handled differently, see below.
1124
g_error("Spread type not supported!");
1126
for (unsigned int i = 0; i < gr->vector.stops.size() - 1; i++) {
1127
double r0 = gr->vector.stops[i].color.v.c[0];
1128
double g0 = gr->vector.stops[i].color.v.c[1];
1129
double b0 = gr->vector.stops[i].color.v.c[2];
1130
double a0 = gr->vector.stops[i].opacity;
1131
double r1 = gr->vector.stops[i+1].color.v.c[0];
1132
double g1 = gr->vector.stops[i+1].color.v.c[1];
1133
double b1 = gr->vector.stops[i+1].color.v.c[2];
1134
double a1 = gr->vector.stops[i+1].opacity;
1135
double o0 = gr->vector.stops[i].offset * (NCOLORS-1);
1136
double o1 = gr->vector.stops[i + 1].offset * (NCOLORS-1);
1137
unsigned int ob = (unsigned int) floor(o0+.5); // These are the first and last element that might be affected by this interval.
1138
unsigned int oe = (unsigned int) floor(o1+.5); // These need to be computed the same to ensure that ob will be covered by the next interval if oe==ob
1141
// Simple case, this interval starts and stops within one cell
1142
// The contribution of this interval is:
1143
// (o1-o0)*(c(o0)+c(o1))/2
1144
// = (o1-o0)*(c0+c1)/2
1145
double dt = 0.5*(o1-o0);
1146
remainder[0] += dt*(r0 + r1);
1147
remainder[1] += dt*(g0 + g1);
1148
remainder[2] += dt*(b0 + b1);
1149
remainder[3] += dt*(a0 + a1);
1151
// First compute colors for the cells which are fully covered by the current interval.
1152
// The prefiltered values are equal to the midpoint of each cell here.
1153
// f = (j-o0)/(o1-o0)
1154
// = j*(1/(o1-o0)) - o0/(o1-o0)
1155
double f = (ob-o0) / (o1-o0);
1156
double df = 1. / (o1-o0);
1157
for (unsigned int j = ob+1; j < oe; j++) {
1159
gr->color[4 * j + 0] = (unsigned char) floor(255*(r0 + f*(r1-r0)) + .5);
1160
gr->color[4 * j + 1] = (unsigned char) floor(255*(g0 + f*(g1-g0)) + .5);
1161
gr->color[4 * j + 2] = (unsigned char) floor(255*(b0 + f*(b1-b0)) + .5);
1162
gr->color[4 * j + 3] = (unsigned char) floor(255*(a0 + f*(a1-a0)) + .5);
1165
// Now handle the beginning
1166
// The contribution of the last point is already in remainder.
1167
// The contribution of this point is:
1168
// (ob+.5-o0)*(c(o0)+c(ob+.5))/2
1169
// = (ob+.5-o0)*c((o0+ob+.5)/2)
1170
// = (ob+.5-o0)*(c0+((o0+ob+.5)/2-o0)*df*(c1-c0))
1171
// = (ob+.5-o0)*(c0+(ob+.5-o0)*df*(c1-c0)/2)
1172
double dt = ob+.5-o0;
1174
if (ob==0 && gr->spread==SP_GRADIENT_SPREAD_REFLECT) {
1175
// The first half of the first cell is just a mirror image of the second half, so simply multiply it by 2.
1176
gr->color[4 * ob + 0] = (unsigned char) floor(2*255*(remainder[0] + dt*(r0 + f*(r1-r0))) + .5);
1177
gr->color[4 * ob + 1] = (unsigned char) floor(2*255*(remainder[1] + dt*(g0 + f*(g1-g0))) + .5);
1178
gr->color[4 * ob + 2] = (unsigned char) floor(2*255*(remainder[2] + dt*(b0 + f*(b1-b0))) + .5);
1179
gr->color[4 * ob + 3] = (unsigned char) floor(2*255*(remainder[3] + dt*(a0 + f*(a1-a0))) + .5);
1180
} else if (ob==0 && gr->spread==SP_GRADIENT_SPREAD_REPEAT) {
1181
// The first cell is the same as the last cell, so save whatever is in the second half here and deal with the rest later.
1182
remainder_for_end[0] = remainder[0] + dt*(r0 + f*(r1-r0));
1183
remainder_for_end[1] = remainder[1] + dt*(g0 + f*(g1-g0));
1184
remainder_for_end[2] = remainder[2] + dt*(b0 + f*(b1-b0));
1185
remainder_for_end[3] = remainder[3] + dt*(a0 + f*(a1-a0));
1187
// The first half of the cell was already in remainder.
1188
gr->color[4 * ob + 0] = (unsigned char) floor(255*(remainder[0] + dt*(r0 + f*(r1-r0))) + .5);
1189
gr->color[4 * ob + 1] = (unsigned char) floor(255*(remainder[1] + dt*(g0 + f*(g1-g0))) + .5);
1190
gr->color[4 * ob + 2] = (unsigned char) floor(255*(remainder[2] + dt*(b0 + f*(b1-b0))) + .5);
1191
gr->color[4 * ob + 3] = (unsigned char) floor(255*(remainder[3] + dt*(a0 + f*(a1-a0))) + .5);
1194
// Now handle the end, which should end up in remainder
1195
// The contribution of this point is:
1196
// (o1-oe+.5)*(c(o1)+c(oe-.5))/2
1197
// = (o1-oe+.5)*c((o1+oe-.5)/2)
1198
// = (o1-oe+.5)*(c0+((o1+oe-.5)/2-o0)*df*(c1-c0))
1200
f = (0.5*(o1+oe-.5)-o0)*df;
1201
remainder[0] = dt*(r0 + f*(r1-r0));
1202
remainder[1] = dt*(g0 + f*(g1-g0));
1203
remainder[2] = dt*(b0 + f*(b1-b0));
1204
remainder[3] = dt*(a0 + f*(a1-a0));
1207
switch(gr->spread) {
1208
case SP_GRADIENT_SPREAD_PAD:
1209
gr->color[4 * (NCOLORS-1) + 0] = (unsigned char) floor(255*(remainder[0]+remainder_for_end[0]) + .5);
1210
gr->color[4 * (NCOLORS-1) + 1] = (unsigned char) floor(255*(remainder[1]+remainder_for_end[1]) + .5);
1211
gr->color[4 * (NCOLORS-1) + 2] = (unsigned char) floor(255*(remainder[2]+remainder_for_end[2]) + .5);
1212
gr->color[4 * (NCOLORS-1) + 3] = (unsigned char) floor(255*(remainder[3]+remainder_for_end[3]) + .5);
1214
case SP_GRADIENT_SPREAD_REFLECT:
1215
// The second half is the same as the first half, so multiply by 2.
1216
gr->color[4 * (NCOLORS-1) + 0] = (unsigned char) floor(2*255*remainder[0] + .5);
1217
gr->color[4 * (NCOLORS-1) + 1] = (unsigned char) floor(2*255*remainder[1] + .5);
1218
gr->color[4 * (NCOLORS-1) + 2] = (unsigned char) floor(2*255*remainder[2] + .5);
1219
gr->color[4 * (NCOLORS-1) + 3] = (unsigned char) floor(2*255*remainder[3] + .5);
1221
case SP_GRADIENT_SPREAD_REPEAT:
1222
// The second half is the same as the second half of the first cell (which was saved in remainder_for_end).
1223
gr->color[0] = gr->color[4 * (NCOLORS-1) + 0] = (unsigned char) floor(255*(remainder[0]+remainder_for_end[0]) + .5);
1224
gr->color[1] = gr->color[4 * (NCOLORS-1) + 1] = (unsigned char) floor(255*(remainder[1]+remainder_for_end[1]) + .5);
1225
gr->color[2] = gr->color[4 * (NCOLORS-1) + 2] = (unsigned char) floor(255*(remainder[2]+remainder_for_end[2]) + .5);
1226
gr->color[3] = gr->color[4 * (NCOLORS-1) + 3] = (unsigned char) floor(255*(remainder[3]+remainder_for_end[3]) + .5);
1232
* Renders gradient vector to buffer as line.
1234
* RGB buffer background should be set up beforehand.
1236
* @param len,width,height,rowstride Buffer parameters (1 or 2 dimensional).
1237
* @param span Full integer width of requested gradient.
1238
* @param pos Buffer starting position in span.
1241
sp_gradient_render_vector_line_rgba(SPGradient *const gradient, guchar *buf,
1242
gint const len, gint const pos, gint const span)
1244
g_return_if_fail(gradient != NULL);
1245
g_return_if_fail(SP_IS_GRADIENT(gradient));
1246
g_return_if_fail(buf != NULL);
1247
g_return_if_fail(len > 0);
1248
g_return_if_fail(pos >= 0);
1249
g_return_if_fail(pos + len <= span);
1250
g_return_if_fail(span > 0);
1252
if (!gradient->color) {
1253
sp_gradient_ensure_colors(gradient);
1256
gint idx = (pos * 1024 << 8) / span;
1257
gint didx = (1024 << 8) / span;
1259
for (gint x = 0; x < len; x++) {
1260
/// \todo Can this be done with 4 byte copies?
1261
*buf++ = gradient->color[4 * (idx >> 8)];
1262
*buf++ = gradient->color[4 * (idx >> 8) + 1];
1263
*buf++ = gradient->color[4 * (idx >> 8) + 2];
1264
*buf++ = gradient->color[4 * (idx >> 8) + 3];
1270
* Render rectangular RGBA area from gradient vector.
1273
sp_gradient_render_vector_block_rgba(SPGradient *const gradient, guchar *buf,
1274
gint const width, gint const height, gint const rowstride,
1275
gint const pos, gint const span, bool const horizontal)
1277
g_return_if_fail(gradient != NULL);
1278
g_return_if_fail(SP_IS_GRADIENT(gradient));
1279
g_return_if_fail(buf != NULL);
1280
g_return_if_fail(width > 0);
1281
g_return_if_fail(height > 0);
1282
g_return_if_fail(pos >= 0);
1283
g_return_if_fail((horizontal && (pos + width <= span)) || (!horizontal && (pos + height <= span)));
1284
g_return_if_fail(span > 0);
1287
sp_gradient_render_vector_line_rgba(gradient, buf, width, pos, span);
1288
for (gint y = 1; y < height; y++) {
1289
memcpy(buf + y * rowstride, buf, 4 * width);
1292
guchar *tmp = (guchar *)alloca(4 * height);
1293
sp_gradient_render_vector_line_rgba(gradient, tmp, height, pos, span);
1294
for (gint y = 0; y < height; y++) {
1295
guchar *b = buf + y * rowstride;
1296
for (gint x = 0; x < width; x++) {
1308
* Render rectangular RGB area from gradient vector.
1311
sp_gradient_render_vector_block_rgb(SPGradient *gradient, guchar *buf,
1312
gint const width, gint const height, gint const /*rowstride*/,
1313
gint const pos, gint const span, bool const horizontal)
1315
g_return_if_fail(gradient != NULL);
1316
g_return_if_fail(SP_IS_GRADIENT(gradient));
1317
g_return_if_fail(buf != NULL);
1318
g_return_if_fail(width > 0);
1319
g_return_if_fail(height > 0);
1320
g_return_if_fail(pos >= 0);
1321
g_return_if_fail((horizontal && (pos + width <= span)) || (!horizontal && (pos + height <= span)));
1322
g_return_if_fail(span > 0);
1325
guchar *tmp = (guchar*)alloca(4 * width);
1326
sp_gradient_render_vector_line_rgba(gradient, tmp, width, pos, span);
1327
for (gint y = 0; y < height; y++) {
1329
for (gint x = 0; x < width; x++) {
1331
gint fc = (t[0] - buf[0]) * a;
1332
buf[0] = buf[0] + ((fc + (fc >> 8) + 0x80) >> 8);
1333
fc = (t[1] - buf[1]) * a;
1334
buf[1] = buf[1] + ((fc + (fc >> 8) + 0x80) >> 8);
1335
fc = (t[2] - buf[2]) * a;
1336
buf[2] = buf[2] + ((fc + (fc >> 8) + 0x80) >> 8);
1342
guchar *tmp = (guchar*)alloca(4 * height);
1343
sp_gradient_render_vector_line_rgba(gradient, tmp, height, pos, span);
1344
for (gint y = 0; y < height; y++) {
1345
guchar *t = tmp + 4 * y;
1346
for (gint x = 0; x < width; x++) {
1348
gint fc = (t[0] - buf[0]) * a;
1349
buf[0] = buf[0] + ((fc + (fc >> 8) + 0x80) >> 8);
1350
fc = (t[1] - buf[1]) * a;
1351
buf[1] = buf[1] + ((fc + (fc >> 8) + 0x80) >> 8);
1352
fc = (t[2] - buf[2]) * a;
1353
buf[2] = buf[2] + ((fc + (fc >> 8) + 0x80) >> 8);
1360
sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Matrix const &ctm, Geom::Rect const &bbox)
1362
if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1096
gstop.color = vector.stops.back().color;
1097
gstop.opacity = vector.stops.back().opacity;
1098
vector.stops.push_back(gstop);
1102
vector.built = true;
1106
sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, Geom::Rect const &bbox)
1108
if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1363
1109
return ( Geom::Scale(bbox.dimensions())
1364
1110
* Geom::Translate(bbox.min())
1365
* Geom::Matrix(ctm) );
1111
* Geom::Affine(ctm) );
1372
sp_gradient_get_gs2d_matrix(SPGradient const *gr, Geom::Matrix const &ctm, Geom::Rect const &bbox)
1118
sp_gradient_get_gs2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, Geom::Rect const &bbox)
1374
if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1120
if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1375
1121
return ( gr->gradientTransform
1376
1122
* Geom::Scale(bbox.dimensions())
1377
1123
* Geom::Translate(bbox.min())
1378
* Geom::Matrix(ctm) );
1124
* Geom::Affine(ctm) );
1380
1126
return gr->gradientTransform * ctm;
1385
sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Matrix const &ctm,
1386
Geom::Rect const &bbox, Geom::Matrix const &gs2d)
1131
sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Affine const &ctm,
1132
Geom::Rect const &bbox, Geom::Affine const &gs2d)
1388
1134
gr->gradientTransform = gs2d * ctm.inverse();
1389
if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX ) {
1135
if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX ) {
1390
1136
gr->gradientTransform = ( gr->gradientTransform
1391
1137
* Geom::Translate(-bbox.min())
1392
1138
* Geom::Scale(bbox.dimensions()).inverse() );
1394
1140
gr->gradientTransform_set = TRUE;
1396
SP_OBJECT(gr)->requestModified(SP_OBJECT_MODIFIED_FLAG);
1142
gr->requestModified(SP_OBJECT_MODIFIED_FLAG);
1400
1146
* Linear Gradient
1405
/// A context with linear gradient, painter, and gradient renderer.
1406
struct SPLGPainter {
1408
SPLinearGradient *lg;
1410
NRLGradientRenderer lgr;
1413
1149
static void sp_lineargradient_class_init(SPLinearGradientClass *klass);
1414
1150
static void sp_lineargradient_init(SPLinearGradient *lg);
1561
* Create linear gradient context.
1563
* Basically we have to deal with transformations
1565
* 1) color2norm - maps point in (0,NCOLORS) vector to (0,1) vector
1566
* 2) norm2pos - maps (0,1) vector to x1,y1 - x2,y2
1567
* 2) gradientTransform
1569
* 4) ctm == userspace to pixel grid
1571
* See also (*) in sp-pattern about why we may need parent_transform.
1573
* \todo (point 1 above) fixme: I do not know how to deal with start > 0
1577
sp_lineargradient_painter_new(SPPaintServer *ps,
1578
Geom::Matrix const &full_transform,
1579
Geom::Matrix const &/*parent_transform*/,
1582
SPLinearGradient *lg = SP_LINEARGRADIENT(ps);
1583
SPGradient *gr = SP_GRADIENT(ps);
1585
if (!gr->color) sp_gradient_ensure_colors(gr);
1587
SPLGPainter *lgp = g_new(SPLGPainter, 1);
1589
lgp->painter.type = SP_PAINTER_IND;
1590
lgp->painter.fill = sp_lg_fill;
1595
* Technically speaking, we map NCOLORS on line [start,end] onto line
1596
* [0,1]. I almost think we should fill color array start and end in
1597
* that case. The alternative would be to leave these just empty garbage
1598
* or something similar. Originally I had 1023.9999 here - not sure
1599
* whether we have really to cut out ceil int (Lauris).
1601
Geom::Matrix color2norm(Geom::identity());
1602
Geom::Matrix color2px;
1603
if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1604
Geom::Matrix norm2pos(Geom::identity());
1606
/* BBox to user coordinate system */
1607
Geom::Matrix bbox2user(bbox->x1 - bbox->x0, 0, 0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0);
1609
Geom::Matrix color2pos = color2norm * norm2pos;
1610
Geom::Matrix color2tpos = color2pos * gr->gradientTransform;
1611
Geom::Matrix color2user = color2tpos * bbox2user;
1612
color2px = color2user * full_transform;
1615
/* Problem: What to do, if we have mixed lengths and percentages? */
1616
/* Currently we do ignore percentages at all, but that is not good (lauris) */
1618
Geom::Matrix norm2pos(Geom::identity());
1619
Geom::Matrix color2pos = color2norm * norm2pos;
1620
Geom::Matrix color2tpos = color2pos * gr->gradientTransform;
1621
color2px = color2tpos * full_transform;
1624
// TODO: remove color2px_nr after converting to 2geom
1625
NR::Matrix color2px_nr = from_2geom(color2px);
1626
nr_lgradient_renderer_setup(&lgp->lgr, gr->color, sp_gradient_get_spread(gr), &color2px_nr,
1627
lg->x1.computed, lg->y1.computed,
1628
lg->x2.computed, lg->y2.computed);
1630
return (SPPainter *) lgp;
1634
sp_lineargradient_painter_free(SPPaintServer */*ps*/, SPPainter *painter)
1640
1289
* Directly set properties of linear gradient and request modified.
1931
1486
rg->fy.set(SVGLength::NONE, fy, fy);
1932
1487
rg->r.set(SVGLength::NONE, r, r);
1934
SP_OBJECT(rg)->requestModified(SP_OBJECT_MODIFIED_FLAG);
1489
rg->requestModified(SP_OBJECT_MODIFIED_FLAG);
1938
* Callback when radial gradient object is rendered.
1492
/* CAIRO RENDERING STUFF */
1941
sp_rg_fill(SPPainter *painter, NRPixBlock *pb)
1943
SPRGPainter *rgp = (SPRGPainter *) painter;
1945
if (rgp->rg->color == NULL) {
1946
sp_gradient_ensure_colors (rgp->rg);
1947
rgp->rgr.vector = rgp->rg->color;
1950
nr_render((NRRenderer *) &rgp->rgr, pb, NULL);
1495
sp_gradient_pattern_common_setup(cairo_pattern_t *cp,
1497
Geom::OptRect const &bbox,
1501
switch (gr->getSpread()) {
1502
case SP_GRADIENT_SPREAD_REFLECT:
1503
cairo_pattern_set_extend(cp, CAIRO_EXTEND_REFLECT);
1505
case SP_GRADIENT_SPREAD_REPEAT:
1506
cairo_pattern_set_extend(cp, CAIRO_EXTEND_REPEAT);
1508
case SP_GRADIENT_SPREAD_PAD:
1510
cairo_pattern_set_extend(cp, CAIRO_EXTEND_PAD);
1515
for (std::vector<SPGradientStop>::iterator i = gr->vector.stops.begin();
1516
i != gr->vector.stops.end(); ++i)
1518
// multiply stop opacity by paint opacity
1519
cairo_pattern_add_color_stop_rgba(cp, i->offset,
1520
i->color.v.c[0], i->color.v.c[1], i->color.v.c[2], i->opacity * opacity);
1523
// set pattern matrix
1524
Geom::Affine gs2user = gr->gradientTransform;
1525
if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1526
Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top());
1527
gs2user *= bbox2user;
1529
ink_cairo_pattern_set_matrix(cp, gs2user.inverse());
1532
static cairo_pattern_t *
1533
sp_radialgradient_create_pattern(SPPaintServer *ps,
1535
Geom::OptRect const &bbox,
1538
SPRadialGradient *rg = SP_RADIALGRADIENT(ps);
1539
SPGradient *gr = SP_GRADIENT(ps);
1543
cairo_pattern_t *cp = cairo_pattern_create_radial(
1544
rg->fx.computed, rg->fy.computed, 0,
1545
rg->cx.computed, rg->cy.computed, rg->r.computed);
1547
sp_gradient_pattern_common_setup(cp, gr, bbox, opacity);
1552
static cairo_pattern_t *
1553
sp_lineargradient_create_pattern(SPPaintServer *ps,
1555
Geom::OptRect const &bbox,
1558
SPLinearGradient *lg = SP_LINEARGRADIENT(ps);
1559
SPGradient *gr = SP_GRADIENT(ps);
1563
cairo_pattern_t *cp = cairo_pattern_create_linear(
1564
lg->x1.computed, lg->y1.computed,
1565
lg->x2.computed, lg->y2.computed);
1567
sp_gradient_pattern_common_setup(cp, gr, bbox, opacity);
1573
sp_gradient_create_preview_pattern(SPGradient *gr, double width)
1577
cairo_pattern_t *pat = cairo_pattern_create_linear(0, 0, width, 0);
1579
for (std::vector<SPGradientStop>::iterator i = gr->vector.stops.begin();
1580
i != gr->vector.stops.end(); ++i)
1582
cairo_pattern_add_color_stop_rgba(pat, i->offset,
1583
i->color.v.c[0], i->color.v.c[1], i->color.v.c[2], i->opacity);