/work/workdir/UnpackedTarball/cairo/src/cairo-pdf-shading.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
2 | | /* cairo - a vector graphics library with display and print output |
3 | | * |
4 | | * Copyright © 2009 Adrian Johnson |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it either under the terms of the GNU Lesser General Public |
8 | | * License version 2.1 as published by the Free Software Foundation |
9 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
10 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
11 | | * notice, a recipient may use your version of this file under either |
12 | | * the MPL or the LGPL. |
13 | | * |
14 | | * You should have received a copy of the LGPL along with this library |
15 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
16 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
17 | | * You should have received a copy of the MPL along with this library |
18 | | * in the file COPYING-MPL-1.1 |
19 | | * |
20 | | * The contents of this file are subject to the Mozilla Public License |
21 | | * Version 1.1 (the "License"); you may not use this file except in |
22 | | * compliance with the License. You may obtain a copy of the License at |
23 | | * http://www.mozilla.org/MPL/ |
24 | | * |
25 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
26 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
27 | | * the specific language governing rights and limitations. |
28 | | * |
29 | | * The Original Code is the cairo graphics library. |
30 | | * |
31 | | * The Initial Developer of the Original Code is Adrian Johnson. |
32 | | * |
33 | | * Contributor(s): |
34 | | * Adrian Johnson <ajohnson@redneon.com> |
35 | | */ |
36 | | |
37 | | #include "cairoint.h" |
38 | | |
39 | | #if CAIRO_HAS_PDF_OPERATORS |
40 | | |
41 | | #include "cairo-pdf-shading-private.h" |
42 | | |
43 | | #include "cairo-array-private.h" |
44 | | #include "cairo-error-private.h" |
45 | | #include <float.h> |
46 | | |
47 | | static unsigned char * |
48 | | encode_coordinate (unsigned char *p, double c) |
49 | 0 | { |
50 | 0 | uint32_t f; |
51 | |
|
52 | 0 | f = c; |
53 | 0 | *p++ = f >> 24; |
54 | 0 | *p++ = (f >> 16) & 0xff; |
55 | 0 | *p++ = (f >> 8) & 0xff; |
56 | 0 | *p++ = f & 0xff; |
57 | |
|
58 | 0 | return p; |
59 | 0 | } |
60 | | |
61 | | static unsigned char * |
62 | | encode_point (unsigned char *p, const cairo_point_double_t *point) |
63 | 0 | { |
64 | 0 | p = encode_coordinate (p, point->x); |
65 | 0 | p = encode_coordinate (p, point->y); |
66 | |
|
67 | 0 | return p; |
68 | 0 | } |
69 | | |
70 | | static unsigned char * |
71 | | encode_color_component (unsigned char *p, double color) |
72 | 0 | { |
73 | 0 | uint16_t c; |
74 | |
|
75 | 0 | c = _cairo_color_double_to_short (color); |
76 | 0 | *p++ = c >> 8; |
77 | 0 | *p++ = c & 0xff; |
78 | |
|
79 | 0 | return p; |
80 | 0 | } |
81 | | |
82 | | static unsigned char * |
83 | | encode_color (unsigned char *p, const cairo_color_t *color) |
84 | 0 | { |
85 | 0 | p = encode_color_component (p, color->red); |
86 | 0 | p = encode_color_component (p, color->green); |
87 | 0 | p = encode_color_component (p, color->blue); |
88 | |
|
89 | 0 | return p; |
90 | 0 | } |
91 | | |
92 | | static unsigned char * |
93 | | encode_alpha (unsigned char *p, const cairo_color_t *color) |
94 | 0 | { |
95 | 0 | p = encode_color_component (p, color->alpha); |
96 | |
|
97 | 0 | return p; |
98 | 0 | } |
99 | | |
100 | | static cairo_status_t |
101 | | _cairo_pdf_shading_generate_decode_array (cairo_pdf_shading_t *shading, |
102 | | const cairo_mesh_pattern_t *mesh, |
103 | | cairo_bool_t is_alpha) |
104 | 0 | { |
105 | 0 | unsigned int num_color_components, i; |
106 | 0 | cairo_bool_t is_valid; |
107 | |
|
108 | 0 | if (is_alpha) |
109 | 0 | num_color_components = 1; |
110 | 0 | else |
111 | 0 | num_color_components = 3; |
112 | |
|
113 | 0 | shading->decode_array_length = 4 + num_color_components * 2; |
114 | 0 | shading->decode_array = _cairo_malloc_ab (shading->decode_array_length, |
115 | 0 | sizeof (double)); |
116 | 0 | if (unlikely (shading->decode_array == NULL)) |
117 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
118 | | |
119 | 0 | is_valid = _cairo_mesh_pattern_coord_box (mesh, |
120 | 0 | &shading->decode_array[0], |
121 | 0 | &shading->decode_array[2], |
122 | 0 | &shading->decode_array[1], |
123 | 0 | &shading->decode_array[3]); |
124 | |
|
125 | 0 | assert (is_valid); |
126 | 0 | assert (shading->decode_array[1] - shading->decode_array[0] >= DBL_EPSILON); |
127 | 0 | assert (shading->decode_array[3] - shading->decode_array[2] >= DBL_EPSILON); |
128 | | |
129 | 0 | for (i = 0; i < num_color_components; i++) { |
130 | 0 | shading->decode_array[4 + 2*i] = 0; |
131 | 0 | shading->decode_array[5 + 2*i] = 1; |
132 | 0 | } |
133 | |
|
134 | 0 | return CAIRO_STATUS_SUCCESS; |
135 | 0 | } |
136 | | |
137 | | /* The ISO32000 specification mandates this order for the points which |
138 | | * define the patch. */ |
139 | | static const int pdf_points_order_i[16] = { |
140 | | 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 }; |
141 | | static const int pdf_points_order_j[16] = { |
142 | | 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 }; |
143 | | |
144 | | static cairo_status_t |
145 | | _cairo_pdf_shading_generate_data (cairo_pdf_shading_t *shading, |
146 | | const cairo_mesh_pattern_t *mesh, |
147 | | cairo_bool_t is_alpha) |
148 | 0 | { |
149 | 0 | const cairo_mesh_patch_t *patch; |
150 | 0 | double x_off, y_off, x_scale, y_scale; |
151 | 0 | unsigned int num_patches; |
152 | 0 | unsigned int num_color_components; |
153 | 0 | unsigned char *p; |
154 | 0 | unsigned int i, j; |
155 | |
|
156 | 0 | if (is_alpha) |
157 | 0 | num_color_components = 1; |
158 | 0 | else |
159 | 0 | num_color_components = 3; |
160 | |
|
161 | 0 | num_patches = _cairo_array_num_elements (&mesh->patches); |
162 | 0 | patch = _cairo_array_index_const (&mesh->patches, 0); |
163 | | |
164 | | /* Each patch requires: |
165 | | * |
166 | | * 1 flag - 1 byte |
167 | | * 16 points. Each point is 2 coordinates. Each coordinate is |
168 | | * stored in 4 bytes. |
169 | | * |
170 | | * 4 colors. Each color is stored in 2 bytes * num_color_components. |
171 | | */ |
172 | 0 | shading->data_length = num_patches * (1 + 16 * 2 * 4 + 4 * 2 * num_color_components); |
173 | 0 | shading->data = _cairo_malloc (shading->data_length); |
174 | 0 | if (unlikely (shading->data == NULL)) |
175 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
176 | | |
177 | 0 | x_off = shading->decode_array[0]; |
178 | 0 | y_off = shading->decode_array[2]; |
179 | 0 | x_scale = UINT32_MAX / (shading->decode_array[1] - x_off); |
180 | 0 | y_scale = UINT32_MAX / (shading->decode_array[3] - y_off); |
181 | |
|
182 | 0 | p = shading->data; |
183 | 0 | for (i = 0; i < num_patches; i++) { |
184 | | /* edge flag */ |
185 | 0 | *p++ = 0; |
186 | | |
187 | | /* 16 points */ |
188 | 0 | for (j = 0; j < 16; j++) { |
189 | 0 | cairo_point_double_t point; |
190 | 0 | int pi, pj; |
191 | |
|
192 | 0 | pi = pdf_points_order_i[j]; |
193 | 0 | pj = pdf_points_order_j[j]; |
194 | 0 | point = patch[i].points[pi][pj]; |
195 | | |
196 | | /* Transform the point as specified in the decode array */ |
197 | 0 | point.x -= x_off; |
198 | 0 | point.y -= y_off; |
199 | 0 | point.x *= x_scale; |
200 | 0 | point.y *= y_scale; |
201 | | |
202 | | /* Make sure that rounding errors don't cause |
203 | | * wraparounds */ |
204 | 0 | point.x = _cairo_restrict_value (point.x, 0, UINT32_MAX); |
205 | 0 | point.y = _cairo_restrict_value (point.y, 0, UINT32_MAX); |
206 | |
|
207 | 0 | p = encode_point (p, &point); |
208 | 0 | } |
209 | | |
210 | | /* 4 colors */ |
211 | 0 | for (j = 0; j < 4; j++) { |
212 | 0 | if (is_alpha) |
213 | 0 | p = encode_alpha (p, &patch[i].colors[j]); |
214 | 0 | else |
215 | 0 | p = encode_color (p, &patch[i].colors[j]); |
216 | 0 | } |
217 | 0 | } |
218 | |
|
219 | 0 | assert (p == shading->data + shading->data_length); |
220 | | |
221 | 0 | return CAIRO_STATUS_SUCCESS; |
222 | 0 | } |
223 | | |
224 | | static cairo_status_t |
225 | | _cairo_pdf_shading_init (cairo_pdf_shading_t *shading, |
226 | | const cairo_mesh_pattern_t *mesh, |
227 | | cairo_bool_t is_alpha) |
228 | 0 | { |
229 | 0 | cairo_status_t status; |
230 | |
|
231 | 0 | assert (mesh->base.status == CAIRO_STATUS_SUCCESS); |
232 | 0 | assert (mesh->current_patch == NULL); |
233 | | |
234 | 0 | shading->shading_type = 7; |
235 | | |
236 | | /* |
237 | | * Coordinates from the minimum to the maximum value of the mesh |
238 | | * map to the [0..UINT32_MAX] range and are represented as |
239 | | * uint32_t values. |
240 | | * |
241 | | * Color components are represented as uint16_t (in a 0.16 fixed |
242 | | * point format, as in the rest of cairo). |
243 | | */ |
244 | 0 | shading->bits_per_coordinate = 32; |
245 | 0 | shading->bits_per_component = 16; |
246 | 0 | shading->bits_per_flag = 8; |
247 | |
|
248 | 0 | shading->decode_array = NULL; |
249 | 0 | shading->data = NULL; |
250 | |
|
251 | 0 | status = _cairo_pdf_shading_generate_decode_array (shading, mesh, is_alpha); |
252 | 0 | if (unlikely (status)) |
253 | 0 | return status; |
254 | | |
255 | 0 | return _cairo_pdf_shading_generate_data (shading, mesh, is_alpha); |
256 | 0 | } |
257 | | |
258 | | cairo_status_t |
259 | | _cairo_pdf_shading_init_color (cairo_pdf_shading_t *shading, |
260 | | const cairo_mesh_pattern_t *pattern) |
261 | 0 | { |
262 | 0 | return _cairo_pdf_shading_init (shading, pattern, FALSE); |
263 | 0 | } |
264 | | |
265 | | cairo_status_t |
266 | | _cairo_pdf_shading_init_alpha (cairo_pdf_shading_t *shading, |
267 | | const cairo_mesh_pattern_t *pattern) |
268 | 0 | { |
269 | 0 | return _cairo_pdf_shading_init (shading, pattern, TRUE); |
270 | 0 | } |
271 | | |
272 | | void |
273 | | _cairo_pdf_shading_fini (cairo_pdf_shading_t *shading) |
274 | 0 | { |
275 | 0 | free (shading->data); |
276 | 0 | free (shading->decode_array); |
277 | 0 | } |
278 | | |
279 | | #endif /* CAIRO_HAS_PDF_OPERATORS */ |