don't crash when loading images > 65kB (fixes #13529)
[swfdec.git] / libswfdec / swfdec_path.c
blobd2da710aecf5eadde1e667fbaa417ab8844a6aad
1 /* Swfdec
2 * Copyright (C) 2003-2006 David Schleef <ds@schleef.org>
3 * 2005-2006 Eric Anholt <eric@anholt.net>
4 * 2006-2007 Benjamin Otte <otte@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #include <string.h>
28 #include "swfdec_path.h"
29 #include "swfdec_debug.h"
31 void
32 swfdec_path_init (cairo_path_t *path)
34 path->status = CAIRO_STATUS_SUCCESS;
35 path->data = NULL;
36 path->num_data = 0;
39 void
40 swfdec_path_reset (cairo_path_t *path)
42 path->status = CAIRO_STATUS_SUCCESS;
43 g_free (path->data);
44 path->data = NULL;
45 path->num_data = 0;
48 void
49 swfdec_path_ensure_size (cairo_path_t *path, int size)
51 #define SWFDEC_PATH_STEPS 32
52 /* round up to next multiple of SWFDEC_PATH_STEPS */
53 int current_size = path->num_data - path->num_data % SWFDEC_PATH_STEPS;
54 if (path->num_data % SWFDEC_PATH_STEPS)
55 current_size += SWFDEC_PATH_STEPS;
57 if (size % SWFDEC_PATH_STEPS)
58 size += SWFDEC_PATH_STEPS - size % SWFDEC_PATH_STEPS;
59 g_assert (current_size % SWFDEC_PATH_STEPS == 0);
60 g_assert (size % SWFDEC_PATH_STEPS == 0);
61 while (size <= current_size)
62 return;
63 SWFDEC_LOG ("extending size of %p from %u to %u", path, current_size, size);
64 path->data = g_renew (cairo_path_data_t, path->data, size);
67 void
68 swfdec_path_move_to (cairo_path_t *path, double x, double y)
70 cairo_path_data_t *cur;
72 swfdec_path_require_size (path, 2);
73 cur = &path->data[path->num_data++];
74 cur->header.type = CAIRO_PATH_MOVE_TO;
75 cur->header.length = 2;
76 cur = &path->data[path->num_data++];
77 cur->point.x = x;
78 cur->point.y = y;
81 void
82 swfdec_path_line_to (cairo_path_t *path, double x, double y)
84 cairo_path_data_t *cur;
86 swfdec_path_require_size (path, 2);
87 cur = &path->data[path->num_data++];
88 cur->header.type = CAIRO_PATH_LINE_TO;
89 cur->header.length = 2;
90 cur = &path->data[path->num_data++];
91 cur->point.x = x;
92 cur->point.y = y;
95 void
96 swfdec_path_curve_to (cairo_path_t *path, double start_x, double start_y,
97 double control_x, double control_y, double end_x, double end_y)
99 cairo_path_data_t *cur;
101 swfdec_path_require_size (path, 4);
102 cur = &path->data[path->num_data++];
103 cur->header.type = CAIRO_PATH_CURVE_TO;
104 cur->header.length = 4;
105 #define WEIGHT (2.0/3.0)
106 cur = &path->data[path->num_data++];
107 cur->point.x = control_x * WEIGHT + (1-WEIGHT) * start_x;
108 cur->point.y = control_y * WEIGHT + (1-WEIGHT) * start_y;
109 cur = &path->data[path->num_data++];
110 cur->point.x = control_x * WEIGHT + (1-WEIGHT) * end_x;
111 cur->point.y = control_y * WEIGHT + (1-WEIGHT) * end_y;
112 cur = &path->data[path->num_data++];
113 cur->point.x = end_x;
114 cur->point.y = end_y;
117 void
118 swfdec_path_append (cairo_path_t *path, const cairo_path_t *append)
120 swfdec_path_require_size (path, append->num_data);
121 memcpy (&path->data[path->num_data], append->data, sizeof (cairo_path_data_t) * append->num_data);
122 path->num_data += append->num_data;
125 void
126 swfdec_path_append_reverse (cairo_path_t *path, const cairo_path_t *append,
127 double x, double y)
129 cairo_path_data_t *out, *in;
130 int i;
132 swfdec_path_require_size (path, append->num_data);
133 path->num_data += append->num_data;
134 out = &path->data[path->num_data - 1];
135 in = append->data;
136 for (i = 0; i < append->num_data; i++) {
137 switch (in[i].header.type) {
138 case CAIRO_PATH_LINE_TO:
139 out[-i].point.x = x;
140 out[-i].point.y = y;
141 out[-i - 1].header = in[i].header;
142 i++;
143 break;
144 case CAIRO_PATH_CURVE_TO:
145 out[-i].point.x = x;
146 out[-i].point.y = y;
147 out[-i - 3].header = in[i].header;
148 out[-i - 1].point = in[i + 1].point;
149 out[-i - 2].point = in[i + 2].point;
150 i += 3;
151 break;
152 case CAIRO_PATH_CLOSE_PATH:
153 case CAIRO_PATH_MOVE_TO:
154 /* these two don't exist in our code */
155 default:
156 g_assert_not_reached ();
158 x = in[i].point.x;
159 y = in[i].point.y;
163 void
164 swfdec_path_get_extents (const cairo_path_t *path, SwfdecRect *extents)
166 cairo_path_data_t *data = path->data;
167 int i;
168 double x = 0, y = 0;
169 gboolean need_current = TRUE;
170 gboolean start = TRUE;
171 #define ADD_POINT(extents, x, y) G_STMT_START { \
172 if (x < extents->x0) \
173 extents->x0 = x; \
174 else if (x > extents->x1) \
175 extents->x1 = x; \
176 if (y < extents->y0) \
177 extents->y0 = y; \
178 else if (y > extents->y1) \
179 extents->y1 = y; \
180 } G_STMT_END
181 for (i = 0; i < path->num_data; i++) {
182 switch (data[i].header.type) {
183 case CAIRO_PATH_CURVE_TO:
184 if (need_current) {
185 if (start) {
186 start = FALSE;
187 extents->x0 = x;
188 extents->x1 = x;
189 extents->y0 = y;
190 extents->y1 = y;
191 } else {
192 ADD_POINT (extents, x, y);
194 need_current = FALSE;
196 ADD_POINT (extents, data[i+1].point.x, data[i+1].point.y);
197 ADD_POINT (extents, data[i+2].point.x, data[i+2].point.y);
198 ADD_POINT (extents, data[i+3].point.x, data[i+3].point.y);
199 i += 3;
200 break;
201 case CAIRO_PATH_LINE_TO:
202 if (need_current) {
203 if (start) {
204 start = FALSE;
205 extents->x0 = x;
206 extents->x1 = x;
207 extents->y0 = y;
208 extents->y1 = y;
209 } else {
210 ADD_POINT (extents, x, y);
212 need_current = FALSE;
214 ADD_POINT (extents, data[i+1].point.x, data[i+1].point.y);
215 i++;
216 break;
217 case CAIRO_PATH_CLOSE_PATH:
218 x = 0;
219 y = 0;
220 need_current = TRUE;
221 break;
222 case CAIRO_PATH_MOVE_TO:
223 x = data[i+1].point.x;
224 y = data[i+1].point.y;
225 need_current = TRUE;
226 i++;
227 break;
228 default:
229 g_assert_not_reached ();
232 #undef ADD_POINT
235 void
236 swfdec_path_merge (cairo_path_t *dest, const cairo_path_t *start,
237 const cairo_path_t *end, double ratio)
239 int i;
240 cairo_path_data_t *ddata, *sdata, *edata;
241 double inv = 1.0 - ratio;
243 g_assert (start->num_data == end->num_data);
245 swfdec_path_reset (dest);
246 swfdec_path_ensure_size (dest, start->num_data);
247 dest->num_data = start->num_data;
248 ddata = dest->data;
249 sdata = start->data;
250 edata = end->data;
251 for (i = 0; i < dest->num_data; i++) {
252 g_assert (sdata[i].header.type == edata[i].header.type);
253 ddata[i] = sdata[i];
254 switch (sdata[i].header.type) {
255 case CAIRO_PATH_CURVE_TO:
256 ddata[i+1].point.x = sdata[i+1].point.x * inv + edata[i+1].point.x * ratio;
257 ddata[i+1].point.y = sdata[i+1].point.y * inv + edata[i+1].point.y * ratio;
258 ddata[i+2].point.x = sdata[i+2].point.x * inv + edata[i+2].point.x * ratio;
259 ddata[i+2].point.y = sdata[i+2].point.y * inv + edata[i+2].point.y * ratio;
260 i += 2;
261 case CAIRO_PATH_MOVE_TO:
262 case CAIRO_PATH_LINE_TO:
263 ddata[i+1].point.x = sdata[i+1].point.x * inv + edata[i+1].point.x * ratio;
264 ddata[i+1].point.y = sdata[i+1].point.y * inv + edata[i+1].point.y * ratio;
265 i++;
266 case CAIRO_PATH_CLOSE_PATH:
267 break;
268 default:
269 g_assert_not_reached ();