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
4 * Copyright © 2009 Adrian Johnson
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.
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
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/
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.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Adrian Johnson.
34 * Adrian Johnson <ajohnson@redneon.com>
39 #if CAIRO_HAS_PDF_OPERATORS
41 #include "cairo-pdf-shading-private.h"
43 #include "cairo-array-private.h"
44 #include "cairo-error-private.h"
47 static unsigned char *
48 encode_coordinate (unsigned char *p
, double c
)
54 *p
++ = (f
>> 16) & 0xff;
55 *p
++ = (f
>> 8) & 0xff;
61 static unsigned char *
62 encode_point (unsigned char *p
, const cairo_point_double_t
*point
)
64 p
= encode_coordinate (p
, point
->x
);
65 p
= encode_coordinate (p
, point
->y
);
70 static unsigned char *
71 encode_color_component (unsigned char *p
, double color
)
75 c
= _cairo_color_double_to_short (color
);
82 static unsigned char *
83 encode_color (unsigned char *p
, const cairo_color_t
*color
)
85 p
= encode_color_component (p
, color
->red
);
86 p
= encode_color_component (p
, color
->green
);
87 p
= encode_color_component (p
, color
->blue
);
92 static unsigned char *
93 encode_alpha (unsigned char *p
, const cairo_color_t
*color
)
95 p
= encode_color_component (p
, color
->alpha
);
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
)
105 unsigned int num_color_components
, i
;
106 cairo_bool_t is_valid
;
109 num_color_components
= 1;
111 num_color_components
= 3;
113 shading
->decode_array_length
= 4 + num_color_components
* 2;
114 shading
->decode_array
= _cairo_malloc_ab (shading
->decode_array_length
,
116 if (unlikely (shading
->decode_array
== NULL
))
117 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
119 is_valid
= _cairo_mesh_pattern_coord_box (mesh
,
120 &shading
->decode_array
[0],
121 &shading
->decode_array
[2],
122 &shading
->decode_array
[1],
123 &shading
->decode_array
[3]);
126 assert (shading
->decode_array
[1] - shading
->decode_array
[0] >= DBL_EPSILON
);
127 assert (shading
->decode_array
[3] - shading
->decode_array
[2] >= DBL_EPSILON
);
129 for (i
= 0; i
< num_color_components
; i
++) {
130 shading
->decode_array
[4 + 2*i
] = 0;
131 shading
->decode_array
[5 + 2*i
] = 1;
134 return CAIRO_STATUS_SUCCESS
;
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 };
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
)
149 const cairo_mesh_patch_t
*patch
;
150 double x_off
, y_off
, x_scale
, y_scale
;
151 unsigned int num_patches
;
152 unsigned int num_color_components
;
157 num_color_components
= 1;
159 num_color_components
= 3;
161 num_patches
= _cairo_array_num_elements (&mesh
->patches
);
162 patch
= _cairo_array_index_const (&mesh
->patches
, 0);
164 /* Each patch requires:
167 * 16 points. Each point is 2 coordinates. Each coordinate is
170 * 4 colors. Each color is stored in 2 bytes * num_color_components.
172 shading
->data_length
= num_patches
* (1 + 16 * 2 * 4 + 4 * 2 * num_color_components
);
173 shading
->data
= malloc (shading
->data_length
);
174 if (unlikely (shading
->data
== NULL
))
175 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
177 x_off
= shading
->decode_array
[0];
178 y_off
= shading
->decode_array
[2];
179 x_scale
= UINT32_MAX
/ (shading
->decode_array
[1] - x_off
);
180 y_scale
= UINT32_MAX
/ (shading
->decode_array
[3] - y_off
);
183 for (i
= 0; i
< num_patches
; i
++) {
188 for (j
= 0; j
< 16; j
++) {
189 cairo_point_double_t point
;
192 pi
= pdf_points_order_i
[j
];
193 pj
= pdf_points_order_j
[j
];
194 point
= patch
[i
].points
[pi
][pj
];
196 /* Transform the point as specified in the decode array */
202 /* Make sure that rounding errors don't cause
204 point
.x
= _cairo_restrict_value (point
.x
, 0, UINT32_MAX
);
205 point
.y
= _cairo_restrict_value (point
.y
, 0, UINT32_MAX
);
207 p
= encode_point (p
, &point
);
211 for (j
= 0; j
< 4; j
++) {
213 p
= encode_alpha (p
, &patch
[i
].colors
[j
]);
215 p
= encode_color (p
, &patch
[i
].colors
[j
]);
219 assert (p
== shading
->data
+ shading
->data_length
);
221 return CAIRO_STATUS_SUCCESS
;
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
)
229 cairo_status_t status
;
231 assert (mesh
->base
.status
== CAIRO_STATUS_SUCCESS
);
232 assert (mesh
->current_patch
== NULL
);
234 shading
->shading_type
= 7;
237 * Coordinates from the minimum to the maximum value of the mesh
238 * map to the [0..UINT32_MAX] range and are represented as
241 * Color components are represented as uint16_t (in a 0.16 fixed
242 * point format, as in the rest of cairo).
244 shading
->bits_per_coordinate
= 32;
245 shading
->bits_per_component
= 16;
246 shading
->bits_per_flag
= 8;
248 shading
->decode_array
= NULL
;
249 shading
->data
= NULL
;
251 status
= _cairo_pdf_shading_generate_decode_array (shading
, mesh
, is_alpha
);
252 if (unlikely (status
))
255 return _cairo_pdf_shading_generate_data (shading
, mesh
, is_alpha
);
259 _cairo_pdf_shading_init_color (cairo_pdf_shading_t
*shading
,
260 const cairo_mesh_pattern_t
*pattern
)
262 return _cairo_pdf_shading_init (shading
, pattern
, FALSE
);
266 _cairo_pdf_shading_init_alpha (cairo_pdf_shading_t
*shading
,
267 const cairo_mesh_pattern_t
*pattern
)
269 return _cairo_pdf_shading_init (shading
, pattern
, TRUE
);
273 _cairo_pdf_shading_fini (cairo_pdf_shading_t
*shading
)
275 free (shading
->data
);
276 free (shading
->decode_array
);
279 #endif /* CAIRO_HAS_PDF_OPERATORS */