fix jsut committed crasher by rewriting startDrag action
[swfdec.git] / libswfdec / swfdec_stroke.c
blobbec454b2f0f79e51614112f2060e775326f30369
1 /* Swfdec
2 * Copyright (C) 2006-2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <math.h>
26 #include "swfdec_stroke.h"
27 #include "swfdec_bits.h"
28 #include "swfdec_color.h"
29 #include "swfdec_debug.h"
30 #include "swfdec_decoder.h"
31 #include "swfdec_image.h"
33 #define MAX_ALIGN 10
35 G_DEFINE_TYPE (SwfdecStroke, swfdec_stroke, G_TYPE_OBJECT);
37 static void
38 swfdec_stroke_append_path_snapped (cairo_t *cr, const cairo_path_t *path)
40 cairo_path_data_t *data;
41 double x, y;
42 int i;
44 data = path->data;
45 for (i = 0; i < path->num_data; i++) {
46 switch (data[i].header.type) {
47 case CAIRO_PATH_MOVE_TO:
48 i++;
49 x = data[i].point.x;
50 y = data[i].point.y;
51 cairo_user_to_device (cr, &x, &y);
52 x = rint (x - 0.5) + 0.5;
53 y = rint (y - 0.5) + 0.5;
54 cairo_device_to_user (cr, &x, &y);
55 /* FIXME: currently we need to clamp this due to extents */
56 x = CLAMP (x, data[i].point.x - MAX_ALIGN, data[i].point.x + MAX_ALIGN);
57 y = CLAMP (y, data[i].point.y - MAX_ALIGN, data[i].point.y + MAX_ALIGN);
58 cairo_move_to (cr, x, y);
59 break;
60 case CAIRO_PATH_LINE_TO:
61 i++;
62 x = data[i].point.x;
63 y = data[i].point.y;
64 cairo_user_to_device (cr, &x, &y);
65 x = rint (x - 0.5) + 0.5;
66 y = rint (y - 0.5) + 0.5;
67 cairo_device_to_user (cr, &x, &y);
68 /* FIXME: currently we need to clamp this due to extents */
69 x = CLAMP (x, data[i].point.x - MAX_ALIGN, data[i].point.x + MAX_ALIGN);
70 y = CLAMP (y, data[i].point.y - MAX_ALIGN, data[i].point.y + MAX_ALIGN);
71 cairo_line_to (cr, x, y);
72 break;
73 case CAIRO_PATH_CURVE_TO:
74 x = data[i+3].point.x;
75 y = data[i+3].point.y;
76 cairo_user_to_device (cr, &x, &y);
77 x = rint (x - 0.5) + 0.5;
78 y = rint (y - 0.5) + 0.5;
79 cairo_device_to_user (cr, &x, &y);
80 /* FIXME: currently we need to clamp this due to extents */
81 x = CLAMP (x, data[i+3].point.x - MAX_ALIGN, data[i+3].point.x + MAX_ALIGN);
82 y = CLAMP (y, data[i+3].point.y - MAX_ALIGN, data[i+3].point.y + MAX_ALIGN);
83 cairo_curve_to (cr, data[i+1].point.x, data[i+1].point.y,
84 data[i+2].point.x, data[i+2].point.y, x, y);
85 i += 3;
86 break;
87 case CAIRO_PATH_CLOSE_PATH:
88 /* doesn't exist in our code */
89 default:
90 g_assert_not_reached ();
95 void
96 swfdec_stroke_paint (SwfdecStroke *stroke, cairo_t *cr, const cairo_path_t *path,
97 const SwfdecColorTransform *trans, guint ratio)
99 SwfdecColor color;
100 double width;
102 g_return_if_fail (SWFDEC_IS_STROKE (stroke));
103 g_return_if_fail (cr != NULL);
104 g_return_if_fail (path != NULL);
105 g_return_if_fail (trans != NULL);
106 g_return_if_fail (ratio < 65536);
108 cairo_set_line_cap (cr, stroke->start_cap);
109 cairo_set_line_join (cr, stroke->join);
110 if (stroke->join == CAIRO_LINE_JOIN_MITER)
111 cairo_set_miter_limit (cr, stroke->miter_limit);
113 swfdec_stroke_append_path_snapped (cr, path);
114 color = swfdec_color_apply_morph (stroke->start_color, stroke->end_color, ratio);
115 color = swfdec_color_apply_transform (color, trans);
116 swfdec_color_set_source (cr, color);
117 if (ratio == 0) {
118 width = stroke->start_width;
119 } else if (ratio == 65535) {
120 width = stroke->end_width;
121 } else {
122 width = (stroke->start_width * (65535 - ratio) + stroke->end_width * ratio) / 65535;
124 if (width < SWFDEC_TWIPS_SCALE_FACTOR)
125 width = SWFDEC_TWIPS_SCALE_FACTOR;
126 cairo_set_line_width (cr, width);
127 cairo_stroke (cr);
130 static void
131 swfdec_stroke_class_init (SwfdecStrokeClass *klass)
135 static void
136 swfdec_stroke_init (SwfdecStroke *stroke)
138 stroke->start_cap = CAIRO_LINE_CAP_ROUND;
139 stroke->end_cap = CAIRO_LINE_CAP_ROUND;
140 stroke->join = CAIRO_LINE_JOIN_ROUND;
143 /*** EXPORTED API ***/
145 SwfdecStroke *
146 swfdec_stroke_parse (SwfdecSwfDecoder *dec)
148 SwfdecBits *bits = &dec->b;
149 SwfdecStroke *stroke = g_object_new (SWFDEC_TYPE_STROKE, NULL);
151 stroke->start_width = swfdec_bits_get_u16 (bits);
152 stroke->end_width = stroke->start_width;
153 stroke->start_color = swfdec_bits_get_color (bits);
154 stroke->end_color = stroke->start_color;
155 SWFDEC_LOG ("new stroke: width %u color %08x", stroke->start_width, stroke->start_color);
157 return stroke;
160 SwfdecStroke *
161 swfdec_stroke_parse_rgba (SwfdecSwfDecoder *dec)
163 SwfdecBits *bits = &dec->b;
164 SwfdecStroke *stroke = g_object_new (SWFDEC_TYPE_STROKE, NULL);
166 stroke->start_width = swfdec_bits_get_u16 (bits);
167 stroke->end_width = stroke->start_width;
168 stroke->start_color = swfdec_bits_get_rgba (bits);
169 stroke->end_color = stroke->start_color;
170 SWFDEC_LOG ("new stroke: width %u color %08x", stroke->start_width, stroke->start_color);
172 return stroke;
175 SwfdecStroke *
176 swfdec_stroke_parse_morph (SwfdecSwfDecoder *dec)
178 SwfdecBits *bits = &dec->b;
179 SwfdecStroke *stroke = g_object_new (SWFDEC_TYPE_STROKE, NULL);
181 stroke->start_width = swfdec_bits_get_u16 (bits);
182 stroke->end_width = swfdec_bits_get_u16 (bits);
183 stroke->start_color = swfdec_bits_get_rgba (bits);
184 stroke->end_color = swfdec_bits_get_rgba (bits);
185 SWFDEC_LOG ("new stroke: width %u => %u color %08X => %08X",
186 stroke->start_width, stroke->end_width,
187 stroke->start_color, stroke->end_color);
189 return stroke;
192 SwfdecStroke *
193 swfdec_stroke_new (guint width, SwfdecColor color)
195 SwfdecStroke *stroke = g_object_new (SWFDEC_TYPE_STROKE, NULL);
197 stroke->start_width = width;
198 stroke->end_width = width;
199 stroke->start_color = color;
200 stroke->end_color = color;
202 return stroke;
205 static cairo_line_cap_t
206 swfdec_line_cap_get (guint cap)
208 switch (cap) {
209 case 0:
210 return CAIRO_LINE_CAP_ROUND;
211 case 1:
212 return CAIRO_LINE_CAP_BUTT;
213 case 2:
214 return CAIRO_LINE_CAP_SQUARE;
215 default:
216 SWFDEC_ERROR ("invalid line cap value %u", cap);
217 return CAIRO_LINE_CAP_ROUND;
220 static cairo_line_join_t
221 swfdec_line_join_get (guint join)
223 switch (join) {
224 case 0:
225 return CAIRO_LINE_JOIN_ROUND;
226 case 1:
227 return CAIRO_LINE_JOIN_BEVEL;
228 case 2:
229 return CAIRO_LINE_JOIN_MITER;
230 default:
231 SWFDEC_ERROR ("invalid line join value %u", join);
232 return CAIRO_LINE_JOIN_ROUND;
236 static SwfdecStroke *
237 swfdec_stroke_do_parse_extended (SwfdecSwfDecoder *dec, gboolean morph)
239 SwfdecBits *bits = &dec->b;
240 guint tmp;
241 gboolean has_pattern;
242 SwfdecStroke *stroke = g_object_new (SWFDEC_TYPE_STROKE, NULL);
244 stroke->start_width = swfdec_bits_get_u16 (bits);
245 if (morph) {
246 stroke->end_width = swfdec_bits_get_u16 (bits);
247 SWFDEC_LOG (" width: %u => %u", stroke->start_width, stroke->end_width);
248 } else {
249 stroke->end_width = stroke->start_width;
250 SWFDEC_LOG (" width: %u", stroke->start_width);
252 tmp = swfdec_bits_getbits (bits, 2);
253 SWFDEC_LOG (" start cap: %u", tmp);
254 stroke->start_cap = swfdec_line_cap_get (tmp);
255 tmp = swfdec_bits_getbits (bits, 2);
256 SWFDEC_LOG (" line join: %u", tmp);
257 stroke->join = swfdec_line_join_get (tmp);
258 has_pattern = swfdec_bits_getbit (bits);
259 SWFDEC_LOG (" has pattern: %d", has_pattern);
260 stroke->no_hscale = swfdec_bits_getbit (bits);
261 SWFDEC_LOG (" no hscale: %d", stroke->no_hscale);
262 stroke->no_vscale = swfdec_bits_getbit (bits);
263 SWFDEC_LOG (" no vscale: %d", stroke->no_vscale);
264 stroke->align_pixel = swfdec_bits_getbit (bits);
265 SWFDEC_LOG (" align pixels: %d", stroke->align_pixel);
266 tmp = swfdec_bits_getbits (bits, 5);
267 stroke->no_close = swfdec_bits_getbit (bits);
268 SWFDEC_LOG (" no close: %d", stroke->no_close);
269 tmp = swfdec_bits_getbits (bits, 2);
270 SWFDEC_LOG (" end cap: %u", tmp);
271 stroke->end_cap = swfdec_line_cap_get (tmp);
272 if (stroke->end_cap != stroke->start_cap) {
273 SWFDEC_WARNING ("FIXME: different caps on start and end of line are unsupported");
275 if (stroke->join == CAIRO_LINE_JOIN_MITER) {
276 stroke->miter_limit = swfdec_bits_get_u16 (bits);
277 SWFDEC_LOG (" miter limit: %u", stroke->miter_limit);
279 if (has_pattern) {
280 if (morph) {
281 stroke->pattern = swfdec_pattern_parse_morph (dec);
282 } else {
283 stroke->pattern = swfdec_pattern_parse_rgba (dec);
285 } else {
286 stroke->start_color = swfdec_bits_get_rgba (bits);
287 if (morph) {
288 stroke->end_color = swfdec_bits_get_rgba (bits);
289 SWFDEC_LOG (" color: #%08X", stroke->start_color);
290 } else {
291 stroke->end_color = stroke->start_color;
292 SWFDEC_LOG (" color: #%08X", stroke->start_color);
296 return stroke;
299 SwfdecStroke *
300 swfdec_stroke_parse_extended (SwfdecSwfDecoder *dec)
302 g_return_val_if_fail (SWFDEC_IS_SWF_DECODER (dec), NULL);
304 return swfdec_stroke_do_parse_extended (dec, FALSE);
307 SwfdecStroke *
308 swfdec_stroke_parse_morph_extended (SwfdecSwfDecoder *dec)
310 g_return_val_if_fail (SWFDEC_IS_SWF_DECODER (dec), NULL);
312 return swfdec_stroke_do_parse_extended (dec, TRUE);