summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gs/base/gdevdrop.c9
-rw-r--r--gs/base/gdevmpla.c256
-rw-r--r--gs/base/gsropt.h8
-rw-r--r--gs/base/gxcht.c4
-rw-r--r--gs/base/gxp1fill.c2
-rw-r--r--gs/doc/Drivers.htm79
6 files changed, 239 insertions, 119 deletions
diff --git a/gs/base/gdevdrop.c b/gs/base/gdevdrop.c
index a6ff9351b..45e0708cc 100644
--- a/gs/base/gdevdrop.c
+++ b/gs/base/gdevdrop.c
@@ -544,6 +544,11 @@ mem_default_strip_copy_rop(gx_device * dev,
GB_COLORS_NATIVE | GB_ALPHA_NONE | GB_DEPTH_ALL |
GB_PACKING_CHUNKY | GB_RETURN_ALL | GB_ALIGN_STANDARD |
GB_OFFSET_0 | GB_OFFSET_ANY | GB_RASTER_STANDARD;
+ const gx_bitmap_format_t no_expand_t_options =
+ GB_COLORS_NATIVE | GB_ALPHA_NONE | GB_DEPTH_ALL |
+ GB_RETURN_ALL | GB_ALIGN_STANDARD |
+ GB_OFFSET_0 | GB_OFFSET_ANY | GB_RASTER_STANDARD |
+ ((lop & lop_t_is_planar) ? GB_PACKING_PLANAR : GB_PACKING_CHUNKY);
const gx_bitmap_format_t expand_options =
(rop_depth > 8 ? GB_COLORS_RGB : GB_COLORS_GRAY) |
GB_ALPHA_NONE | GB_DEPTH_8 |
@@ -578,6 +583,7 @@ mem_default_strip_copy_rop(gx_device * dev,
gs_get_bits_params_t bit_params;
gs_get_bits_params_t expand_params;
gs_get_bits_params_t no_expand_params;
+ gs_get_bits_params_t no_expand_t_params;
int max_height;
int block_height, loop_height;
int code;
@@ -637,6 +643,7 @@ mem_default_strip_copy_rop(gx_device * dev,
expand_s = scolors == 0 && uses_s;
expand_t = tcolors == 0 && uses_t;
no_expand_params.options = no_expand_options;
+ no_expand_t_params.options = no_expand_t_options;
if (expand_t) {
/*
* We don't want to wrap around more than once in Y when
@@ -710,7 +717,7 @@ mem_default_strip_copy_rop(gx_device * dev,
rect.q.y = py + loop_height;
expand_params.data[0] = texture_row;
gx_get_bits_copy(dev, 0, textures->rep_width, loop_height,
- &expand_params, &no_expand_params,
+ &expand_params, &no_expand_t_params,
textures->data + rep_y * textures->raster,
textures->raster);
/*
diff --git a/gs/base/gdevmpla.c b/gs/base/gdevmpla.c
index 46c0eb360..955efe58b 100644
--- a/gs/base/gdevmpla.c
+++ b/gs/base/gdevmpla.c
@@ -1524,6 +1524,100 @@ plane_strip_copy_rop(gx_device_memory * mdev,
return code;
}
+/*
+ * Repack planar into chunky format. This is an internal procedure that
+ * implements the straightforward chunky case of get_bits_rectangle, and
+ * is also used for the general cases.
+ */
+static int
+planar_to_chunky(gx_device_memory *mdev, int x, int y, int w, int h,
+ int offset, uint draster, byte *dest, byte **line_ptrs,
+ int plane_height)
+{
+ int num_planes = mdev->num_planes;
+ sample_load_declare(sptr[GX_DEVICE_COLOR_MAX_COMPONENTS],
+ sbit[GX_DEVICE_COLOR_MAX_COMPONENTS]);
+ sample_store_declare(dptr, dbit, dbbyte);
+ int ddepth = mdev->color_info.depth;
+ int direct =
+ (mdev->color_info.depth != num_planes * mdev->plane_depth ? 0 :
+ mdev->planes[0].shift == 0 ? -mdev->plane_depth : mdev->plane_depth);
+ int pi, ix, iy;
+
+ /* Check whether the planes are of equal size and sequential. */
+ /* If direct != 0, we already know they exactly fill the depth. */
+ if (direct < 0) {
+ for (pi = 0; pi < num_planes; ++pi)
+ if (mdev->planes[pi].shift != pi * -direct) {
+ direct = 0; break;
+ }
+ } else if (direct > 0) {
+ for (pi = 0; pi < num_planes; ++pi)
+ if (mdev->planes[num_planes - 1 - pi].shift != pi * direct) {
+ direct = 0; break;
+ }
+ }
+ for (iy = y; iy < y + h; ++iy) {
+ byte **line_ptr = line_ptrs + iy;
+
+ for (pi = 0; pi < num_planes; ++pi, line_ptr += plane_height) {
+ int plane_depth = mdev->planes[pi].depth;
+ int xbit = x * plane_depth;
+
+ sptr[pi] = *line_ptr + (xbit >> 3);
+ sample_load_setup(sbit[pi], xbit & 7, plane_depth);
+ }
+ {
+ int xbit = offset * ddepth;
+
+ dptr = dest + (iy - y) * draster + (xbit >> 3);
+ sample_store_setup(dbit, xbit & 7, ddepth);
+ }
+ if (direct == -8) {
+ /* 1 byte per component, lsb first. */
+ switch (num_planes) {
+ case 3: {
+ const byte *p0 = sptr[2];
+ const byte *p1 = sptr[1];
+ const byte *p2 = sptr[0];
+
+ for (ix = w; ix > 0; --ix, dptr += 3) {
+ dptr[0] = *p0++;
+ dptr[1] = *p1++;
+ dptr[2] = *p2++;
+ }
+ }
+ continue;
+ case 4:
+ for (ix = w; ix > 0; --ix, dptr += 4) {
+ dptr[0] = *sptr[3]++;
+ dptr[1] = *sptr[2]++;
+ dptr[2] = *sptr[1]++;
+ dptr[3] = *sptr[0]++;
+ }
+ continue;
+ default:
+ break;
+ }
+ }
+ sample_store_preload(dbbyte, dptr, dbit, ddepth);
+ for (ix = w; ix > 0; --ix) {
+ gx_color_index color = 0;
+
+ for (pi = 0; pi < num_planes; ++pi) {
+ int plane_depth = mdev->planes[pi].depth;
+ uint value;
+
+ sample_load_next16(value, sptr[pi], sbit[pi], plane_depth);
+ color |= (gx_color_index)value << mdev->planes[pi].shift;
+ }
+ sample_store_next_any(color, dptr, dbit, ddepth, dbbyte);
+ }
+ sample_store_flush(dptr, dbit, ddepth, dbbyte);
+ }
+ return 0;
+}
+
static byte cmykrop[256] =
{
255,127,191,63,223,95,159,31,239,111,175,47,207,79,143,15,
@@ -1557,6 +1651,69 @@ mem_planar_strip_copy_rop(gx_device * dev,
gx_device_memory * const mdev = (gx_device_memory *)dev;
int plane, code;
+ if (lop & lop_t_is_planar) {
+ /* T is in planar format; expand it to a temporary buffer, then
+ * call ourselves back with a modified rop to use it, then free
+ * the temporary buffer, and return. */
+ /* Make a temporary buffer that contains both the raster and the line
+ * pointers for the buffer. For now, for the sake of sanity, we
+ * convert whole lines of t, but only as many lines as we have to
+ * (unless it loops). */
+ /* We assume that tcolors == NULL here */
+ int ty, i;
+ uint chunky_t_raster;
+ uint chunky_t_height;
+ uint nbytes;
+ byte **line_ptrs;
+ byte *tbuf, *buf;
+ gx_strip_bitmap newtex;
+
+ ty = (y + phase_y) % textures->rep_height;
+ chunky_t_raster = bitmap_raster(textures->rep_width * mdev->color_info.depth);
+ if (ty + height <= textures->rep_height) {
+ chunky_t_height = height;
+ phase_y = -y;
+ } else {
+ ty = 0;
+ chunky_t_height = textures->rep_height;
+ }
+ nbytes = chunky_t_height * chunky_t_raster;
+ buf = gs_alloc_bytes(mdev->memory, nbytes, "mem_planar_strip_copy_rop(buf)");
+ if (buf == NULL) {
+ return gs_note_error(gs_error_VMerror);
+ }
+ nbytes = sizeof(byte *) * mdev->num_planes * textures->rep_height;
+ line_ptrs = (byte **)gs_alloc_bytes(mdev->memory, nbytes, "mem_planar_strip_copy_rop(line_ptrs)");
+ if (line_ptrs == NULL) {
+ gs_free_object(mdev->memory, buf, "mem_planar_strip_copy_rop(buf)");
+ return gs_note_error(gs_error_VMerror);
+ }
+ tbuf = textures->data;
+ for (i = textures->rep_height * mdev->num_planes; i > 0; i--) {
+ *line_ptrs++ = tbuf;
+ tbuf += textures->raster;
+ }
+ line_ptrs -= textures->rep_height * mdev->num_planes;
+ planar_to_chunky(mdev, 0, ty, textures->rep_width, chunky_t_height,
+ 0, chunky_t_raster, buf, line_ptrs, textures->rep_height);
+ gs_free_object(mdev->memory, line_ptrs, "mem_planar_strip_copy_rop(line_ptrs)");
+ for (i = 0; i < chunky_t_height * chunky_t_raster; i++) {
+ if ((((buf[i] & 0x01) == 0) && ((buf[i] & 0x0e) != 0)) ||
+ (((buf[i] & 0x10) == 0) && ((buf[i] & 0xee) != 0))) {
+ dlprintf("ass!\n");
+ }
+ }
+ newtex = *textures;
+ newtex.data = buf;
+ newtex.raster = chunky_t_raster;
+ code = mem_planar_strip_copy_rop(dev, sdata, sourcex, sraster,
+ id, scolors, &newtex, tcolors,
+ x, y, width, height, phase_x, phase_y,
+ lop & ~lop_t_is_planar);
+ gs_free_object(mdev->memory, buf, "mem_planar_strip_copy_rop(buf)");
+ return code;
+ }
+
if ((lop & lop_planar) == 0) {
/* Not doing a planar lop. If we carry on down the default path here,
* we'll end up doing a planar_to_chunky; we may be able to sidestep
@@ -1629,99 +1786,6 @@ mem_planar_strip_copy_rop(gx_device * dev,
phase_x, phase_y, lop, plane);
}
-/*
- * Repack planar into chunky format. This is an internal procedure that
- * implements the straightforward chunky case of get_bits_rectangle, and
- * is also used for the general cases.
- */
-static int
-planar_to_chunky(gx_device_memory *mdev, int x, int y, int w, int h,
- int offset, uint draster, byte *dest)
-{
- int num_planes = mdev->num_planes;
- sample_load_declare(sptr[GX_DEVICE_COLOR_MAX_COMPONENTS],
- sbit[GX_DEVICE_COLOR_MAX_COMPONENTS]);
- sample_store_declare(dptr, dbit, dbbyte);
- int ddepth = mdev->color_info.depth;
- int direct =
- (mdev->color_info.depth != num_planes * mdev->plane_depth ? 0 :
- mdev->planes[0].shift == 0 ? -mdev->plane_depth : mdev->plane_depth);
- int pi, ix, iy;
-
- /* Check whether the planes are of equal size and sequential. */
- /* If direct != 0, we already know they exactly fill the depth. */
- if (direct < 0) {
- for (pi = 0; pi < num_planes; ++pi)
- if (mdev->planes[pi].shift != pi * -direct) {
- direct = 0; break;
- }
- } else if (direct > 0) {
- for (pi = 0; pi < num_planes; ++pi)
- if (mdev->planes[num_planes - 1 - pi].shift != pi * direct) {
- direct = 0; break;
- }
- }
- for (iy = y; iy < y + h; ++iy) {
- byte **line_ptr = mdev->line_ptrs + iy;
-
- for (pi = 0; pi < num_planes; ++pi, line_ptr += mdev->height) {
- int plane_depth = mdev->planes[pi].depth;
- int xbit = x * plane_depth;
-
- sptr[pi] = *line_ptr + (xbit >> 3);
- sample_load_setup(sbit[pi], xbit & 7, plane_depth);
- }
- {
- int xbit = offset * ddepth;
-
- dptr = dest + (iy - y) * draster + (xbit >> 3);
- sample_store_setup(dbit, xbit & 7, ddepth);
- }
- if (direct == -8) {
- /* 1 byte per component, lsb first. */
- switch (num_planes) {
- case 3: {
- const byte *p0 = sptr[2];
- const byte *p1 = sptr[1];
- const byte *p2 = sptr[0];
-
- for (ix = w; ix > 0; --ix, dptr += 3) {
- dptr[0] = *p0++;
- dptr[1] = *p1++;
- dptr[2] = *p2++;
- }
- }
- continue;
- case 4:
- for (ix = w; ix > 0; --ix, dptr += 4) {
- dptr[0] = *sptr[3]++;
- dptr[1] = *sptr[2]++;
- dptr[2] = *sptr[1]++;
- dptr[3] = *sptr[0]++;
- }
- continue;
- default:
- break;
- }
- }
- sample_store_preload(dbbyte, dptr, dbit, ddepth);
- for (ix = w; ix > 0; --ix) {
- gx_color_index color = 0;
-
- for (pi = 0; pi < num_planes; ++pi) {
- int plane_depth = mdev->planes[pi].depth;
- uint value;
-
- sample_load_next16(value, sptr[pi], sbit[pi], plane_depth);
- color |= (gx_color_index)value << mdev->planes[pi].shift;
- }
- sample_store_next_any(color, dptr, dbit, ddepth, dbbyte);
- }
- sample_store_flush(dptr, dbit, ddepth, dbbyte);
- }
- return 0;
-}
-
/* Copy bits back from a planar memory device. */
static int
mem_planar_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
@@ -1841,7 +1905,8 @@ mem_planar_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
(options & GB_RASTER_SPECIFIED ? params->raster :
bitmap_raster((offset + w) * mdev->color_info.depth));
- planar_to_chunky(mdev, x, y, w, h, offset, draster, params->data[0]);
+ planar_to_chunky(mdev, x, y, w, h, offset, draster, params->data[0],
+ mdev->line_ptrs, mdev->height);
} else {
/*
* Do the transfer through an intermediate buffer.
@@ -1895,7 +1960,8 @@ mem_planar_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect,
ch = min(bh, y + h - cy);
for (cx = x; cx < x + w; cx += cw) {
cw = min(bw, x + w - cx);
- planar_to_chunky(mdev, cx, cy, cw, ch, 0, br, buf.b);
+ planar_to_chunky(mdev, cx, cy, cw, ch, 0, br, buf.b,
+ mdev->line_ptrs, mdev->height);
code = gx_get_bits_copy(dev, 0, cw, ch, &dest_params,
&copy_params, buf.b, br);
if (code < 0)
diff --git a/gs/base/gsropt.h b/gs/base/gsropt.h
index 095b51ab8..fc06aa7de 100644
--- a/gs/base/gsropt.h
+++ b/gs/base/gsropt.h
@@ -212,11 +212,15 @@ typedef enum {
/* Also, we abuse the lop even further, by allowing it to specify a specific
* plane for an operation to work on (in a planar device context). To specify
- * a particularp plane, set lop_planar, and then or in the plane number
+ * a particular plane, set lop_planar, and then or in the plane number
* shifted up by lop_planar_shift.
*/
#define lop_planar 0x800
-#define lop_planar_shift 12
+#define lop_planar_shift 13
+
+/* And one final abuse; in strip_copy_rop, we allow the lop to have another
+ * flag bit, indicating that the texture is already in planar format. */
+#define lop_t_is_planar 0x1000
typedef uint gs_logical_operation_t;
diff --git a/gs/base/gxcht.c b/gs/base/gxcht.c
index c6b9f90b4..9716c4679 100644
--- a/gs/base/gxcht.c
+++ b/gs/base/gxcht.c
@@ -26,6 +26,7 @@
#include "gxistate.h"
#include "gzht.h"
#include "gsserial.h"
+#include "gxdevsop.h"
/* Define whether to force use of the slow code, for testing. */
#define USE_SLOW_CODE 0
@@ -583,8 +584,7 @@ gx_dc_ht_colored_fill_rectangle(const gx_device_color * pdevc,
#if USE_SLOW_CODE
set_ht_colors_gt_4
#else
- (dev_proc(dev, map_cmyk_color) == gx_default_encode_color &&
- dev->color_info.depth == 4) ?
+ (dev_proc(dev, dev_spec_op)(dev, gxdso_is_std_cmyk_1bit, NULL, 0) > 0) ?
set_cmyk_1bit_colors :
nplanes <= 4 ? set_ht_colors_le_4 :
set_ht_colors_gt_4
diff --git a/gs/base/gxp1fill.c b/gs/base/gxp1fill.c
index 95d824e39..18ae9cc4c 100644
--- a/gs/base/gxp1fill.c
+++ b/gs/base/gxp1fill.c
@@ -281,7 +281,7 @@ tile_colored_fill(const tile_fill_state_t * ptfs,
x, y, w, h,
imod(xoff - x, data_tile.rep_width),
imod(yoff - y, data_tile.rep_height),
- lop);
+ lop | (ptfs->num_planes > 0 ? lop_t_is_planar : 0));
}
return code;
}
diff --git a/gs/doc/Drivers.htm b/gs/doc/Drivers.htm
index 3521bdffd..717436040 100644
--- a/gs/doc/Drivers.htm
+++ b/gs/doc/Drivers.htm
@@ -804,10 +804,35 @@ used in new code. Here is a copy of the relevant part of the file:
* W and a repetition height of H, the pixel at coordinate (X,Y)
* corresponds to halftone pixel (X mod W, Y mod H), ignoring phase;
* for a shifted halftone with shift S, the pixel at (X,Y) corresponds
- * to halftone pixel ((X + S * floor(Y/H)) mod W, Y mod H). Requirements:
- * strip_shift &lt; rep_width
- * strip_height % rep_height = 0
- * shift = (strip_shift * (size.y / strip_height)) % rep_width
+ * to halftone pixel ((X + S * floor(Y/H)) mod W, Y mod H). In other words,
+ * each Y increment of H shifts the strip left by S pixels.
+ *
+ * As for non-shifted tiles, a strip bitmap may include multiple copies
+ * in X or Y to reduce loop overhead. In this case, we must distinguish:
+ * - The height of an individual strip, which is the same as
+ * the height of the bitmap being replicated (rep_height, H);
+ * - The height of the entire bitmap (size.y).
+ * Similarly, we must distinguish:
+ * - The shift per strip (rep_shift, S);
+ * - The shift for the entire bitmap (shift).
+ * Note that shift = (rep_shift * size.y / rep_height) mod rep_width,
+ * so the shift member of the structure is only an accelerator. It is,
+ * however, an important one, since it indicates whether the overall
+ * bitmap requires shifting or not.
+ *
+ * Note that for shifted tiles, size.y is the size of the stored bitmap
+ * (1 or more strips), and NOT the height of the actual tile. The latter
+ * is not stored in the structure at all: it can be computed as H * W /
+ * gcd(S, W).
+ *
+ * If the bitmap consists of a multiple of W / gcd(S, W) copies in Y, the
+ * effective shift is zero, reducing it to a tile. For simplicity, we
+ * require that if shift is non-zero, the bitmap height be less than H * W /
+ * gcd(S, W). I.e., we don't allow strip bitmaps that are large enough to
+ * include a complete tile but that don't include an integral number of
+ * tiles. Requirements:
+ * rep_shift &lt; rep_width
+ * shift = (rep_shift * (size.y / rep_height)) % rep_width
*/
typedef struct gx_strip_bitmap_s {
byte *data;
@@ -815,8 +840,7 @@ typedef struct gx_strip_bitmap_s {
gs_int_point size; /* width, height */
gx_bitmap_id id;
ushort rep_width, rep_height; /* true size of tile */
- ushort strip_height;
- ushort strip_shift;
+ ushort rep_shift;
ushort shift;
} gx_strip_bitmap;</pre>
</blockquote>
@@ -1753,11 +1777,30 @@ replicated or clipped as needed.
<tr valign=top> <td>9
<td>&nbsp;
<td>0 if texture opaque, 1 if texture transparent
-<tr valign=top> <td>?-10
+<tr valign=top> <td>10
+ <td>&nbsp;
+ <td>1 if pdf transparency is in use, 0 otherwise. This makes no
+difference to the rendering, but forces the raster operation to be considered
+non-idempotent by internal routines.
+<tr valign=top> <td>11
<td>&nbsp;
- <td>unused, must be 0
+ <td>1 if the target of this operation is a specific plane, rather
+than all planes. The plane in question is given by bits 13 upwards. This
+is only used by the planar device.
+<tr valign=top> <td>12
+ <td>&nbsp;
+ <td>1 if the texture plane (T) of this operation is in planar format,
+rather than the default chunky format. This is only used by the planar device.
+<tr valign=top> <td>13-
+ <td>&nbsp;
+ <td>If bit 12 = 1, then bits 13 upwards give the plane number to
+operate on. Otherwise, should be set to 0.
</table></blockquote>
+<p>In general most devices should just check to see that bits they do not
+handle (11 and above typically) are zero, and should jump to the default
+implementation, or return an error otherwise.
+
<p>
The raster operation follows the Microsoft and H-P specification. It is an
8-element truth table that specifies the output value for each of the
@@ -2011,7 +2054,7 @@ components in the device (process) color model.
<dd>
The implementation fills entire triangle.
The filling rule is same as for <a href="#Polygon_level_drawing">Polygon-level drawing</a>.
-A color for each pixel within the triangle to be computed as a linear interpolation
+The color of each pixel within the triangle is computed as a linear interpolation
of vertex colors.
<dd>
The implementation may reject the request if the area or the color appears too complex
@@ -2022,12 +2065,12 @@ into smaller triangles and call the function again with smaller areas.
<b><em>Important note :</em></b> Do not try to decompose the area within
the implementation of <code> fill_linear_color_triangle</code>, because
it can break the plane coverage contiguity and cause a dropout.
-Instead request that graphics library to perform the decomposition.
+Instead request that the graphics library should perform the decomposition.
The graphics libary is smart enough to do that properly.
<dd>
<b><em>Important note :</em></b>
The implementation must handle a special case, when only 2 colors are specified.
-It happens if <code>p3</code> one is <code>NULL</code>.
+It happens if <code>p2</code> is <code>NULL</code>.
This means that the color does not depend on the X coordinate,
i.e. it forms a linear gradient along the Y axis.
The implementation must not reject (return 0) such cases.
@@ -2041,7 +2084,7 @@ fist drop (ignore) the sign bit, then drop least significant bits -
so many ones as you need to fit the device color precision.
<dd>
<b><em>Important note :</em></b> The <code>fa</code> argument may contain
-the <code>swap_axes</code> bit set. In this case the implementation must swap (transpoze)
+the <code>swap_axes</code> bit set. In this case the implementation must swap (transpose)
<code>X</code> and <code>Y</code> axes.
<dd>
<b><em>Important note :</em></b> The implementation must not paint outside the
@@ -2049,7 +2092,7 @@ clipping rectangle specified in the <code>fa</code> argument.
If <code>fa-&gt;swap_axes</code> is true, the clipping rectangle is transposed.
<dd>
See <code> gx_default_fill_linear_color_triangle </code>
-in <code>gdevddrw.c</code> as a sample code.
+in <code>gdevddrw.c</code> for sample code.
</dl>
@@ -2066,9 +2109,9 @@ in <code>gdevddrw.c</code> as a sample code.
The default implementation of <code> fill_linear_color_triangle </code>
calls this function 1-2 times per triangle. Besides that,
this function may be called by the graphics library for other special cases,
-when a decomposition into triangles appears undiserable.
+when a decomposition into triangles appears undesirable.
<dd>
-Rather the prototype can specify a bilinear color,
+While the prototype can specify a bilinear color,
we assume that the implementation handles linear colors only.
This means that the implementation can ignore any of <code> c0, c1, c2, c3 </code>.
The graphics library takes a special care of the color linearity
@@ -2076,12 +2119,12 @@ when calling this function. The reason for passing all 4 color arguments
is to avoid color precision problems.
<dd>
Similarly to <code> fill_linear_color_triangle </code>,
-this function may be called with only 2 colors, and may reject too comple areas.
+this function may be called with only 2 colors, and may reject areas as being too complex.
All those important notes are applicable here.
<dd>
-A sample code may be found in in <code>gxdtfill.h</code>, rather it's a kind of complicated.
+Sample code may be found in in <code>gxdtfill.h</code>; be aware it's rather complicated.
A linear color function is generated from it as <code> gx_fill_trapezoid_ns_lc </code>
-with the following template parametres :
+with the following template parameters :
<pre>
#define LINEAR_COLOR 1