source: trunk/third/librsvg/art_render_gradient.c @ 17277

Revision 17277, 8.2 KB checked in by amb, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17276, which included commits to RCS files with non-trunk default branches.
Line 
1/* This file is adapted from art_render_gradient.c in Libart version 2.3.0 */
2
3#include <libart_lgpl/libart-features.h>
4
5#if LIBART_MAJOR_VERSION == 2 && LIBART_MINOR_VERSION < 3
6
7/*
8 * art_render_gradient.c: Gradient image source for modular rendering.
9 *
10 * Libart_LGPL - library of basic graphic primitives
11 * Copyright (C) 2000 Raph Levien
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 * Library General Public License for more details.
22 *
23 * You should have received a copy of the GNU Library General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 * Boston, MA 02111-1307, USA.
27 *
28 * Authors: Raph Levien <raph@acm.org>
29 *          Alexander Larsson <alla@lysator.liu.se>
30 */
31
32#include <math.h>
33
34#include <libart_lgpl/art_misc.h>
35#include <libart_lgpl/art_alphagamma.h>
36#include <libart_lgpl/art_filterlevel.h>
37
38#include "art_render.h"
39#include "art_render_gradient.h"
40
41typedef struct _ArtImageSourceGradLin ArtImageSourceGradLin;
42typedef struct _ArtImageSourceGradRad ArtImageSourceGradRad;
43
44struct _ArtImageSourceGradLin {
45  ArtImageSource super;
46  const ArtGradientLinear *gradient;
47};
48
49struct _ArtImageSourceGradRad {
50  ArtImageSource super;
51  const ArtGradientRadial *gradient;
52  double a;
53};
54
55#define EPSILON 1e-6
56
57/**
58 * art_render_gradient_setpix: Set a gradient pixel.
59 * @render: The render object.
60 * @dst: Pointer to destination (where to store pixel).
61 * @n_stops: Number of stops in @stops.
62 * @stops: The stops for the gradient.
63 * @offset: The offset.
64 *
65 * @n_stops must be > 0.
66 *
67 * Sets a gradient pixel, storing it at @dst.
68 **/
69static void
70art_render_gradient_setpix (ArtRender *render,
71                            art_u8 *dst,
72                            int n_stops, ArtGradientStop *stops,
73                            double offset)
74{
75  int ix;
76  int j;
77  double off0, off1;
78  int n_ch = render->n_chan + 1;
79
80  for (ix = 0; ix < n_stops; ix++)
81    if (stops[ix].offset > offset)
82      break;
83  /* stops[ix - 1].offset < offset < stops[ix].offset */
84  if (ix > 0 && ix < n_stops)
85    {
86      off0 = stops[ix - 1].offset;
87      off1 = stops[ix].offset;
88      if (fabs (off1 - off0) > EPSILON)
89        {
90          double interp;
91
92          interp = (offset - off0) / (off1 - off0);
93          for (j = 0; j < n_ch; j++)
94            {
95              int z0, z1;
96              int z;
97              z0 = stops[ix - 1].color[j];
98              z1 = stops[ix].color[j];
99              z = floor (z0 + (z1 - z0) * interp + 0.5);
100              if (render->buf_depth == 8)
101                dst[j] = ART_PIX_8_FROM_MAX (z);
102              else /* (render->buf_depth == 16) */
103                ((art_u16 *)dst)[j] = z;
104            }
105          return;
106        }
107    }
108  else if (ix == n_stops)
109    ix--;
110
111  for (j = 0; j < n_ch; j++)
112    {
113      int z;
114      z = stops[ix].color[j];
115      if (render->buf_depth == 8)
116        dst[j] = ART_PIX_8_FROM_MAX (z);
117      else /* (render->buf_depth == 16) */
118        ((art_u16 *)dst)[j] = z;
119    }
120}
121
122static void
123art_render_gradient_linear_done (ArtRenderCallback *self, ArtRender *render)
124{
125  art_free (self);
126}
127
128static void
129art_render_gradient_linear_render (ArtRenderCallback *self, ArtRender *render,
130                                   art_u8 *dest, int y)
131{
132  ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self;
133  const ArtGradientLinear *gradient = z->gradient;
134  int pixstride = (render->n_chan + 1) * (render->depth >> 3);
135  int x;
136  int width = render->x1 - render->x0;
137  double offset, d_offset;
138  double actual_offset;
139  int n_stops = gradient->n_stops;
140  ArtGradientStop *stops = gradient->stops;
141  art_u8 *bufp = render->image_buf;
142  ArtGradientSpread spread = gradient->spread;
143
144  offset = render->x0 * gradient->a + y * gradient->b + gradient->c;
145  d_offset = gradient->a;
146
147  for (x = 0; x < width; x++)
148    {
149      if (spread == ART_GRADIENT_PAD)
150        actual_offset = offset;
151      else if (spread == ART_GRADIENT_REPEAT)
152        actual_offset = offset - floor (offset);
153      else /* (spread == ART_GRADIENT_REFLECT) */
154        {
155          double tmp;
156
157          tmp = offset - 2 * floor (0.5 * offset);
158          actual_offset = tmp > 1 ? 2 - tmp : tmp;
159        }
160      art_render_gradient_setpix (render, bufp, n_stops, stops, actual_offset);
161      offset += d_offset;
162      bufp += pixstride;
163    }
164}
165
166static void
167art_render_gradient_linear_negotiate (ArtImageSource *self, ArtRender *render,
168                                      ArtImageSourceFlags *p_flags,
169                                      int *p_buf_depth, ArtAlphaType *p_alpha)
170{
171  self->super.render = art_render_gradient_linear_render;
172  *p_flags = 0;
173  *p_buf_depth = render->depth;
174  *p_alpha = ART_ALPHA_PREMUL;
175}
176
177/**
178 * art_render_gradient_linear: Add a linear gradient image source.
179 * @render: The render object.
180 * @gradient: The linear gradient.
181 *
182 * Adds the linear gradient @gradient as the image source for rendering
183 * in the render object @render.
184 **/
185void
186art_render_gradient_linear (ArtRender *render,
187                            const ArtGradientLinear *gradient,
188                            ArtFilterLevel level)
189{
190  ArtImageSourceGradLin *image_source = art_new (ArtImageSourceGradLin, 1);
191
192  image_source->super.super.render = NULL;
193  image_source->super.super.done = art_render_gradient_linear_done;
194  image_source->super.negotiate = art_render_gradient_linear_negotiate;
195
196  image_source->gradient = gradient;
197
198  art_render_add_image_source (render, &image_source->super);
199}
200
201static void
202art_render_gradient_radial_done (ArtRenderCallback *self, ArtRender *render)
203{
204  art_free (self);
205}
206
207static void
208art_render_gradient_radial_render (ArtRenderCallback *self, ArtRender *render,
209                                   art_u8 *dest, int y)
210{
211  ArtImageSourceGradRad *z = (ArtImageSourceGradRad *)self;
212  const ArtGradientRadial *gradient = z->gradient;
213  int pixstride = (render->n_chan + 1) * (render->depth >> 3);
214  int x;
215  int x0 = render->x0;
216  int width = render->x1 - x0;
217  int n_stops = gradient->n_stops;
218  ArtGradientStop *stops = gradient->stops;
219  art_u8 *bufp = render->image_buf;
220  double fx = gradient->fx;
221  double fy = gradient->fy;
222  double dx, dy;
223  double *affine = gradient->affine;
224  double aff0 = affine[0];
225  double aff1 = affine[1];
226  const double a = z->a;
227  const double arecip = 1.0 / a;
228  double b, db;
229  double c, dc, ddc;
230  double b_a, db_a;
231  double rad, drad, ddrad;
232
233  dx = x0 * aff0 + y * affine[2] + affine[4] - fx;
234  dy = x0 * aff1 + y * affine[3] + affine[5] - fy;
235  b = dx * fx + dy * fy;
236  db = aff0 * fx + aff1 * fy;
237  c = dx * dx + dy * dy;
238  dc = 2 * aff0 * dx + aff0 * aff0 + 2 * aff1 * dy + aff1 * aff1;
239  ddc = 2 * aff0 * aff0 + 2 * aff1 * aff1;
240
241  b_a = b * arecip;
242  db_a = db * arecip;
243
244  rad = b_a * b_a + c * arecip;
245  drad = 2 * b_a * db_a + db_a * db_a + dc * arecip;
246  ddrad = 2 * db_a * db_a + ddc * arecip;
247
248  for (x = 0; x < width; x++)
249    {
250      double z;
251
252      if (rad > 0)
253        z = b_a + sqrt (rad);
254      else
255        z = b_a;
256      art_render_gradient_setpix (render, bufp, n_stops, stops, z);
257      bufp += pixstride;
258      b_a += db_a;
259      rad += drad;
260      drad += ddrad;
261    }
262}
263
264static void
265art_render_gradient_radial_negotiate (ArtImageSource *self, ArtRender *render,
266                                      ArtImageSourceFlags *p_flags,
267                                      int *p_buf_depth, ArtAlphaType *p_alpha)
268{
269  self->super.render = art_render_gradient_radial_render;
270  *p_flags = 0;
271  *p_buf_depth = render->depth;
272  *p_alpha = ART_ALPHA_PREMUL;
273}
274
275/**
276 * art_render_gradient_radial: Add a radial gradient image source.
277 * @render: The render object.
278 * @gradient: The radial gradient.
279 *
280 * Adds the radial gradient @gradient as the image source for rendering
281 * in the render object @render.
282 **/
283void
284art_render_gradient_radial (ArtRender *render,
285                            const ArtGradientRadial *gradient,
286                            ArtFilterLevel level)
287{
288  ArtImageSourceGradRad *image_source = art_new (ArtImageSourceGradRad, 1);
289  double fx = gradient->fx;
290  double fy = gradient->fy;
291
292  image_source->super.super.render = NULL;
293  image_source->super.super.done = art_render_gradient_radial_done;
294  image_source->super.negotiate = art_render_gradient_radial_negotiate;
295
296  image_source->gradient = gradient;
297  /* todo: sanitycheck fx, fy? */
298  image_source->a = 1 - fx * fx - fy * fy;
299
300  art_render_add_image_source (render, &image_source->super);
301}
302
303#endif
Note: See TracBrowser for help on using the repository browser.