~ubuntu-branches/ubuntu/oneiric/evince/oneiric-updates

« back to all changes in this revision

Viewing changes to backend/impress/r_gradient.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-01-10 19:35:11 UTC
  • mto: (1.3.1 experimental) (52.1.1 hardy-proposed)
  • mto: This revision was merged to the branch mainline in revision 20.
  • Revision ID: james.westby@ubuntu.com-20070110193511-yjrnndv8e8wv03yy
Tags: upstream-0.7.1
ImportĀ upstreamĀ versionĀ 0.7.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* imposter (OO.org Impress viewer)
 
2
** Copyright (C) 2003-2005 Gurer Ozen
 
3
** This code is free software; you can redistribute it and/or
 
4
** modify it under the terms of GNU General Public License.
 
5
*/
 
6
 
 
7
#include "common.h"
 
8
#include "internal.h"
 
9
#include <math.h>
 
10
 
 
11
#define GRAD_LINEAR 0
 
12
#define GRAD_AXIAL 1
 
13
#define GRAD_SQUARE 2
 
14
#define GRAD_RECTANGULAR 3
 
15
#define GRAD_RADIAL 4
 
16
#define GRAD_ELLIPTICAL 5
 
17
 
 
18
typedef struct Gradient_s {
 
19
        int type;
 
20
        ImpColor start;
 
21
        int start_intensity;
 
22
        ImpColor end;
 
23
        int end_intensity;
 
24
        int angle;
 
25
        int border;
 
26
        int steps;
 
27
        int offset_x;
 
28
        int offset_y;
 
29
} Gradient;
 
30
 
 
31
typedef struct Rectangle_s {
 
32
        int Left;
 
33
        int Top;
 
34
        int Right;
 
35
        int Bottom;
 
36
} Rectangle;
 
37
 
 
38
static void
 
39
poly_rotate (ImpPoint *poly, int n, int cx, int cy, double fAngle)
 
40
{
 
41
        int i;
 
42
        long nX, nY;
 
43
 
 
44
        for (i = 0; i < n; i++) {
 
45
                nX = poly->x - cx;
 
46
                nY = poly->y - cy;
 
47
                poly->x = (cos(fAngle) * nX + sin(fAngle) * nY) + cx;
 
48
                poly->y = - (sin(fAngle)* nX - cos(fAngle) * nY) + cy;
 
49
                poly++;
 
50
        }
 
51
}
 
52
 
 
53
static void
 
54
r_draw_gradient_simple (ImpRenderCtx *ctx, void *drw_data, Gradient *grad)
 
55
{
 
56
        Rectangle rRect = { 0, 0, ctx->pix_w - 1, ctx->pix_h - 1 };
 
57
        Rectangle aRect, aFullRect;
 
58
        ImpPoint poly[4], tempoly[2];
 
59
        ImpColor gcol;
 
60
        double fW, fH, fDX, fDY, fAngle;
 
61
        double fScanLine, fScanInc;
 
62
        long redSteps, greenSteps, blueSteps;
 
63
        long nBorder;
 
64
        int i, nSteps, nSteps2;
 
65
        int cx, cy;
 
66
 
 
67
        cx = rRect.Left + (rRect.Right - rRect.Left) / 2;
 
68
        cy = rRect.Top + (rRect.Bottom - rRect.Top) / 2;
 
69
 
 
70
        aRect = rRect;
 
71
        aRect.Top--; aRect.Left--; aRect.Bottom++; aRect.Right++;
 
72
        fW = rRect.Right - rRect.Left;
 
73
        fH = rRect.Bottom - rRect.Top;
 
74
        fAngle = (((double) grad->angle) * 3.14 / 1800.0);
 
75
        fDX = fW * fabs (cos (fAngle)) + fH * fabs (sin (fAngle));
 
76
        fDY = fH * fabs (cos (fAngle)) + fW * fabs (sin (fAngle));
 
77
        fDX = (fDX - fW) * 0.5 - 0.5;
 
78
        fDY = (fDY - fH) * 0.5 - 0.5;
 
79
        aRect.Left -= fDX;
 
80
        aRect.Right += fDX;
 
81
        aRect.Top -= fDY;
 
82
        aRect.Bottom += fDY;
 
83
        aFullRect = aRect;
 
84
 
 
85
        nBorder = grad->border * (aRect.Bottom - aRect.Top) / 100;
 
86
        if (grad->type == GRAD_LINEAR) {
 
87
                aRect.Top += nBorder;
 
88
        } else {
 
89
                nBorder >>= 1;
 
90
                aRect.Top += nBorder;
 
91
                aRect.Bottom -= nBorder;
 
92
        }
 
93
 
 
94
        if (aRect.Top > (aRect.Bottom - 1))
 
95
                aRect.Top = aRect.Bottom - 1;
 
96
 
 
97
        poly[0].x = aFullRect.Left;
 
98
        poly[0].y = aFullRect.Top;
 
99
        poly[1].x = aFullRect.Right;
 
100
        poly[1].y = aFullRect.Top;
 
101
        poly[2].x = aRect.Right;
 
102
        poly[2].y = aRect.Top;
 
103
        poly[3].x = aRect.Left;
 
104
        poly[3].y = aRect.Top;
 
105
        poly_rotate (&poly[0], 4, cx, cy, fAngle);
 
106
 
 
107
        redSteps = grad->end.red - grad->start.red;
 
108
        greenSteps = grad->end.green - grad->start.green;
 
109
        blueSteps = grad->end.blue - grad->start.blue;
 
110
        nSteps = grad->steps;
 
111
        if (nSteps == 0) {
 
112
                long mr;
 
113
                mr = aRect.Bottom - aRect.Top;
 
114
                if (mr < 50)
 
115
                        nSteps = mr / 2;
 
116
                else
 
117
                        nSteps = mr / 4;
 
118
                mr = abs(redSteps);
 
119
                if (abs(greenSteps) > mr) mr = abs(greenSteps);
 
120
                if (abs(blueSteps) > mr) mr = abs(blueSteps);
 
121
                if (mr < nSteps) nSteps = mr;
 
122
        }
 
123
 
 
124
        if (grad->type == GRAD_AXIAL) {
 
125
                if (nSteps & 1) nSteps++;
 
126
                nSteps2 = nSteps + 2;
 
127
                gcol = grad->end;
 
128
                redSteps <<= 1;
 
129
                greenSteps <<= 1;
 
130
                blueSteps <<= 1;
 
131
        } else {
 
132
                nSteps2 = nSteps + 1;
 
133
                gcol = grad->start;
 
134
        }
 
135
 
 
136
        fScanLine = aRect.Top;
 
137
        fScanInc  = (double)(aRect.Bottom - aRect.Top) / (double)nSteps;
 
138
 
 
139
        for (i = 0; i < nSteps2; i++) {
 
140
                // draw polygon
 
141
                ctx->drw->set_fg_color(drw_data, &gcol);
 
142
                ctx->drw->draw_polygon(drw_data, 1, &poly[0], 4);
 
143
                // calc next polygon
 
144
                aRect.Top = (long)(fScanLine += fScanInc);
 
145
                if (i == nSteps) {
 
146
                        tempoly[0].x = aFullRect.Left;
 
147
                        tempoly[0].y = aFullRect.Bottom;
 
148
                        tempoly[1].x = aFullRect.Right;
 
149
                        tempoly[1].y = aFullRect.Bottom;
 
150
                } else {
 
151
                        tempoly[0].x = aRect.Left;
 
152
                        tempoly[0].y = aRect.Top;
 
153
                        tempoly[1].x = aRect.Right;
 
154
                        tempoly[1].y = aRect.Top;
 
155
                }
 
156
                poly_rotate (&tempoly[0], 2, cx, cy, fAngle);
 
157
                poly[0] = poly[3];
 
158
                poly[1] = poly[2];
 
159
                poly[2] = tempoly[1];
 
160
                poly[3] = tempoly[0];
 
161
                // calc next color
 
162
                if (grad->type == GRAD_LINEAR) {
 
163
                        gcol.red = grad->start.red + ((redSteps * i) / nSteps2);
 
164
                        gcol.green = grad->start.green + ((greenSteps * i) / nSteps2);
 
165
                        gcol.blue = grad->start.blue + ((blueSteps * i) / nSteps2);
 
166
                } else {
 
167
                        if (i >= nSteps) {
 
168
                                gcol.red = grad->end.red;
 
169
                                gcol.green = grad->end.green;
 
170
                                gcol.blue = grad->end.blue;
 
171
                        } else {
 
172
                                if (i <= (nSteps / 2)) {
 
173
                                        gcol.red = grad->end.red - ((redSteps * i) / nSteps2);
 
174
                                        gcol.green = grad->end.green - ((greenSteps * i) / nSteps2);
 
175
                                        gcol.blue = grad->end.blue - ((blueSteps * i) / nSteps2);
 
176
                                } else {
 
177
                                        int i2 = i - nSteps / 2;
 
178
                                        gcol.red = grad->start.red + ((redSteps * i2) / nSteps2);
 
179
                                        gcol.green = grad->start.green + ((greenSteps * i2) / nSteps2);
 
180
                                        gcol.blue = grad->start.blue + ((blueSteps * i2) / nSteps2);
 
181
                                }
 
182
                        }
 
183
                }
 
184
        }
 
185
}
 
186
 
 
187
static void
 
188
r_draw_gradient_complex (ImpRenderCtx *ctx, void *drw_data, Gradient *grad)
 
189
{
 
190
        Rectangle rRect = { 0, 0, ctx->pix_w - 1, ctx->pix_h - 1 };
 
191
        Rectangle aRect = rRect;
 
192
        ImpColor gcol;
 
193
        ImpPoint poly[4];
 
194
        double fAngle = (((double) grad->angle) * 3.14 / 1800.0);
 
195
        long redSteps, greenSteps, blueSteps;
 
196
        long nZW, nZH;
 
197
        long bX, bY;
 
198
        long sW, sH;
 
199
        long cx, cy;
 
200
        int i;
 
201
        long nSteps;
 
202
        double sTop, sLeft, sRight, sBottom, sInc;
 
203
        int minRect;
 
204
 
 
205
        redSteps = grad->end.red - grad->start.red;
 
206
        greenSteps = grad->end.green - grad->start.green;
 
207
        blueSteps = grad->end.blue - grad->start.blue;
 
208
 
 
209
        if (grad->type == GRAD_SQUARE || grad->type == GRAD_RECTANGULAR) {
 
210
                double fW = aRect.Right - aRect.Left;
 
211
                double fH = aRect.Bottom - aRect.Top;
 
212
                double fDX = fW * fabs (cos (fAngle)) + fH * fabs (sin (fAngle));
 
213
                double fDY = fH * fabs (cos (fAngle)) + fW * fabs (sin (fAngle));
 
214
                fDX = (fDX - fW) * 0.5 - 0.5;
 
215
                fDY = (fDY - fH) * 0.5 - 0.5;
 
216
                aRect.Left -= fDX;
 
217
                aRect.Right += fDX;
 
218
                aRect.Top -= fDY;
 
219
                aRect.Bottom += fDY;
 
220
        }
 
221
 
 
222
        sW = aRect.Right - aRect.Left;
 
223
        sH = aRect.Bottom - aRect.Top;
 
224
 
 
225
        if (grad->type == GRAD_SQUARE) {
 
226
                if (sW > sH) sH = sW; else sW = sH;
 
227
        } else if (grad->type == GRAD_RADIAL) {
 
228
                sW = 0.5 + sqrt ((double)sW*(double)sW + (double)sH*(double)sH);
 
229
                sH = sW;
 
230
        } else if (grad->type == GRAD_ELLIPTICAL) {
 
231
                sW = 0.5 + (double)sW * 1.4142;
 
232
                sH = 0.5 + (double)sH * 1.4142;
 
233
        }
 
234
 
 
235
        nZW = (aRect.Right - aRect.Left) * grad->offset_x / 100;
 
236
        nZH = (aRect.Bottom - aRect.Top) * grad->offset_y / 100;
 
237
        bX = grad->border * sW / 100;
 
238
        bY = grad->border * sH / 100;
 
239
        cx = aRect.Left + nZW;
 
240
        cy = aRect.Top + nZH;
 
241
 
 
242
        sW -= bX;
 
243
        sH -= bY;
 
244
 
 
245
        aRect.Left = cx - ((aRect.Right - aRect.Left) >> 1);
 
246
        aRect.Top = cy - ((aRect.Bottom - aRect.Top) >> 1);
 
247
 
 
248
        nSteps = grad->steps;
 
249
        minRect = aRect.Right - aRect.Left;
 
250
        if (aRect.Bottom - aRect.Top < minRect) minRect = aRect.Bottom - aRect.Top;
 
251
        if (nSteps == 0) {
 
252
                long mr;
 
253
                if (minRect < 50)
 
254
                        nSteps = minRect / 2;
 
255
                else
 
256
                        nSteps = minRect / 4;
 
257
                mr = abs(redSteps);
 
258
                if (abs(greenSteps) > mr) mr = abs(greenSteps);
 
259
                if (abs(blueSteps) > mr) mr = abs(blueSteps);
 
260
                if (mr < nSteps) nSteps = mr;
 
261
        }
 
262
 
 
263
        sLeft = aRect.Left;
 
264
        sTop = aRect.Top;
 
265
        sRight = aRect.Right;
 
266
        sBottom = aRect.Bottom;
 
267
        sInc = (double) minRect / (double) nSteps * 0.5;
 
268
 
 
269
        gcol = grad->start;
 
270
        poly[0].x = rRect.Left;
 
271
        poly[0].y = rRect.Top;
 
272
        poly[1].x = rRect.Right;
 
273
        poly[1].y = rRect.Top;
 
274
        poly[2].x = rRect.Right;
 
275
        poly[2].y = rRect.Bottom;
 
276
        poly[3].x = rRect.Left;
 
277
        poly[3].y = rRect.Bottom;
 
278
        ctx->drw->set_fg_color(drw_data, &gcol);
 
279
        ctx->drw->draw_polygon(drw_data, 1, &poly[0], 4);
 
280
 
 
281
        for (i = 0; i < nSteps; i++) {
 
282
                aRect.Left = (long) (sLeft += sInc);
 
283
                aRect.Top = (long) (sTop += sInc);
 
284
                aRect.Right = (long) (sRight -= sInc);
 
285
                aRect.Bottom = (long) (sBottom -= sInc);
 
286
                if (aRect.Bottom - aRect.Top < 2 || aRect.Right - aRect.Left < 2)
 
287
                        break;
 
288
 
 
289
                gcol.red = grad->start.red + (redSteps * (i+1) / nSteps);
 
290
                gcol.green = grad->start.green + (greenSteps * (i+1) / nSteps);
 
291
                gcol.blue = grad->start.blue + (blueSteps * (i+1) / nSteps);
 
292
                ctx->drw->set_fg_color(drw_data, &gcol);
 
293
 
 
294
                if (grad->type == GRAD_RADIAL || grad->type == GRAD_ELLIPTICAL) {
 
295
                        ctx->drw->draw_arc(drw_data, 1, aRect.Left, aRect.Top,
 
296
                                aRect.Right - aRect.Left, aRect.Bottom - aRect.Top,
 
297
                                0, 360);
 
298
                } else {
 
299
                        poly[0].x = aRect.Left;
 
300
                        poly[0].y = aRect.Top;
 
301
                        poly[1].x = aRect.Right;
 
302
                        poly[1].y = aRect.Top;
 
303
                        poly[2].x = aRect.Right;
 
304
                        poly[2].y = aRect.Bottom;
 
305
                        poly[3].x = aRect.Left;
 
306
                        poly[3].y = aRect.Bottom;
 
307
                        poly_rotate (&poly[0], 4, cx, cy, fAngle);
 
308
                        ctx->drw->draw_polygon(drw_data, 1, &poly[0], 4);
 
309
                }
 
310
        }
 
311
}
 
312
 
 
313
void
 
314
r_draw_gradient (ImpRenderCtx *ctx, void *drw_data, iks *node)
 
315
{
 
316
//      GdkGC *gc;
 
317
        Gradient grad;
 
318
        char *stil, *tmp;
 
319
        iks *x;
 
320
 
 
321
        stil = r_get_style (ctx, node, "draw:fill-gradient-name");
 
322
        x = iks_find_with_attrib (iks_find (ctx->styles, "office:styles"),
 
323
                "draw:gradient", "draw:name", stil);
 
324
        if (x) {
 
325
                memset (&grad, 0, sizeof (Gradient));
 
326
                grad.type = -1;
 
327
                grad.offset_x = 50;
 
328
                grad.offset_y = 50;
 
329
 
 
330
                tmp = iks_find_attrib (x, "draw:start-color");
 
331
                if (tmp) r_parse_color (tmp, &grad.start);
 
332
                tmp = iks_find_attrib (x, "draw:start-intensity");
 
333
                if (tmp) {
 
334
                        int val = atoi (tmp);
 
335
                        grad.start.red = grad.start.red * val / 100;
 
336
                        grad.start.green = grad.start.green * val / 100;
 
337
                        grad.start.blue = grad.start.blue * val / 100;
 
338
                }
 
339
                tmp = iks_find_attrib (x, "draw:end-color");
 
340
                if (tmp) r_parse_color (tmp, &grad.end);
 
341
                tmp = iks_find_attrib (x, "draw:end-intensity");
 
342
                if (tmp) {
 
343
                        int val = atoi (tmp);
 
344
                        grad.end.red = grad.end.red * val / 100;
 
345
                        grad.end.green = grad.end.green * val / 100;
 
346
                        grad.end.blue = grad.end.blue * val / 100;
 
347
                }
 
348
                tmp = iks_find_attrib (x, "draw:angle");
 
349
                if (tmp) grad.angle = atoi(tmp) % 3600;
 
350
                tmp = iks_find_attrib (x, "draw:border");
 
351
                if (tmp) grad.border = atoi(tmp);
 
352
                tmp = r_get_style (ctx, node, "draw:gradient-step-count");
 
353
                if (tmp) grad.steps = atoi (tmp);
 
354
                tmp = iks_find_attrib (x, "draw:cx");
 
355
                if (tmp) grad.offset_x = atoi (tmp);
 
356
                tmp = iks_find_attrib (x, "draw:cy");
 
357
                if (tmp) grad.offset_y = atoi (tmp);
 
358
                tmp = iks_find_attrib (x, "draw:style");
 
359
                if (iks_strcmp (tmp, "linear") == 0)
 
360
                        grad.type = GRAD_LINEAR;
 
361
                else if (iks_strcmp (tmp, "axial") == 0)
 
362
                        grad.type = GRAD_AXIAL;
 
363
                else if (iks_strcmp (tmp, "radial") == 0)
 
364
                        grad.type = GRAD_RADIAL;
 
365
                else if (iks_strcmp (tmp, "rectangular") == 0)
 
366
                        grad.type = GRAD_RECTANGULAR;
 
367
                else if (iks_strcmp (tmp, "ellipsoid") == 0)
 
368
                        grad.type = GRAD_ELLIPTICAL;
 
369
                else if (iks_strcmp (tmp, "square") == 0)
 
370
                        grad.type = GRAD_SQUARE;
 
371
 
 
372
                if (grad.type == -1) return;
 
373
 
 
374
//              gc = ctx->gc;
 
375
//              ctx->gc = gdk_gc_new (ctx->d);
 
376
//              gdk_gc_copy (ctx->gc, gc);
 
377
 
 
378
                if (grad.type == GRAD_LINEAR || grad.type == GRAD_AXIAL)
 
379
                        r_draw_gradient_simple (ctx, drw_data, &grad);
 
380
                else
 
381
                        r_draw_gradient_complex (ctx, drw_data, &grad);
 
382
 
 
383
//              gdk_gc_unref (ctx->gc);
 
384
//              ctx->gc = gc;
 
385
        }
 
386
}