1 #define __NR_ARENA_GROUP_C__
3 /*
4 * RGBA display list system for inkscape
5 *
6 * Author:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 *
9 * Copyright (C) 2001-2002 Lauris Kaplinski
10 * Copyright (C) 2001 Ximian, Inc.
11 *
12 * Released under GNU GPL, read the file 'COPYING' for more information
13 */
15 #include "display/nr-arena-group.h"
16 #include "display/nr-filter.h"
17 #include "display/nr-filter-gaussian.h"
18 #include "display/nr-filter-types.h"
19 #include "style.h"
20 #include "sp-filter.h"
21 #include "sp-gaussian-blur.h"
23 static void nr_arena_group_class_init (NRArenaGroupClass *klass);
24 static void nr_arena_group_init (NRArenaGroup *group);
26 static NRArenaItem *nr_arena_group_children (NRArenaItem *item);
27 static NRArenaItem *nr_arena_group_last_child (NRArenaItem *item);
28 static void nr_arena_group_add_child (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
29 static void nr_arena_group_remove_child (NRArenaItem *item, NRArenaItem *child);
30 static void nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref);
32 static unsigned int nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset);
33 static unsigned int nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags);
34 static unsigned int nr_arena_group_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb);
35 static NRArenaItem *nr_arena_group_pick (NRArenaItem *item, NR::Point p, double delta, unsigned int sticky);
37 static NRArenaItemClass *parent_class;
39 NRType
40 nr_arena_group_get_type (void)
41 {
42 static NRType type = 0;
43 if (!type) {
44 type = nr_object_register_type (NR_TYPE_ARENA_ITEM,
45 "NRArenaGroup",
46 sizeof (NRArenaGroupClass),
47 sizeof (NRArenaGroup),
48 (void (*) (NRObjectClass *)) nr_arena_group_class_init,
49 (void (*) (NRObject *)) nr_arena_group_init);
50 }
51 return type;
52 }
54 static void
55 nr_arena_group_class_init (NRArenaGroupClass *klass)
56 {
57 NRObjectClass *object_class;
58 NRArenaItemClass *item_class;
60 object_class = (NRObjectClass *) klass;
61 item_class = (NRArenaItemClass *) klass;
63 parent_class = (NRArenaItemClass *) ((NRObjectClass *) klass)->parent;
65 object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaGroup>;
67 item_class->children = nr_arena_group_children;
68 item_class->last_child = nr_arena_group_last_child;
69 item_class->add_child = nr_arena_group_add_child;
70 item_class->set_child_position = nr_arena_group_set_child_position;
71 item_class->remove_child = nr_arena_group_remove_child;
72 item_class->update = nr_arena_group_update;
73 item_class->render = nr_arena_group_render;
74 item_class->clip = nr_arena_group_clip;
75 item_class->pick = nr_arena_group_pick;
76 }
78 static void
79 nr_arena_group_init (NRArenaGroup *group)
80 {
81 group->transparent = FALSE;
82 group->children = NULL;
83 group->last = NULL;
84 group->style = NULL;
85 nr_matrix_set_identity (&group->child_transform);
86 }
88 static NRArenaItem *
89 nr_arena_group_children (NRArenaItem *item)
90 {
91 NRArenaGroup *group = NR_ARENA_GROUP (item);
93 return group->children;
94 }
96 static NRArenaItem *
97 nr_arena_group_last_child (NRArenaItem *item)
98 {
99 NRArenaGroup *group = NR_ARENA_GROUP (item);
101 return group->last;
102 }
104 static void
105 nr_arena_group_add_child (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref)
106 {
107 NRArenaGroup *group = NR_ARENA_GROUP (item);
109 if (!ref) {
110 group->children = nr_arena_item_attach (item, child, NULL, group->children);
111 } else {
112 ref->next = nr_arena_item_attach (item, child, ref, ref->next);
113 }
115 if (ref == group->last) group->last = child;
117 nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, FALSE);
118 }
120 static void
121 nr_arena_group_remove_child (NRArenaItem *item, NRArenaItem *child)
122 {
123 NRArenaGroup *group = NR_ARENA_GROUP (item);
125 if (child == group->last) group->last = child->prev;
127 if (child->prev) {
128 nr_arena_item_detach (item, child);
129 } else {
130 group->children = nr_arena_item_detach (item, child);
131 }
133 nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, FALSE);
134 }
136 static void
137 nr_arena_group_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref)
138 {
139 NRArenaGroup *group = NR_ARENA_GROUP (item);
141 if (child == group->last) group->last = child->prev;
143 if (child->prev) {
144 nr_arena_item_detach (item, child);
145 } else {
146 group->children = nr_arena_item_detach (item, child);
147 }
149 if (!ref) {
150 group->children = nr_arena_item_attach (item, child, NULL, group->children);
151 } else {
152 ref->next = nr_arena_item_attach (item, child, ref, ref->next);
153 }
155 if (ref == group->last) group->last = child;
157 nr_arena_item_request_render (child);
158 }
160 static unsigned int
161 nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset)
162 {
163 unsigned int newstate;
165 NRArenaGroup *group = NR_ARENA_GROUP (item);
167 unsigned int beststate = NR_ARENA_ITEM_STATE_ALL;
169 for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
170 NRGC cgc(gc);
171 nr_matrix_multiply (&cgc.transform, &group->child_transform, &gc->transform);
172 newstate = nr_arena_item_invoke_update (child, area, &cgc, state, reset);
173 beststate = beststate & newstate;
174 }
176 if (beststate & NR_ARENA_ITEM_STATE_BBOX) {
177 nr_rect_l_set_empty (&item->bbox);
178 for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
179 nr_rect_l_union (&item->bbox, &item->bbox, &child->bbox);
180 }
181 }
183 return beststate;
184 }
186 void nr_arena_group_set_style (NRArenaGroup *group, SPStyle *style)
187 {
188 g_return_if_fail(group != NULL);
189 g_return_if_fail(NR_IS_ARENA_GROUP(group));
191 if (style) sp_style_ref(style);
192 if (group->style) sp_style_unref(group->style);
193 group->style = style;
195 //if there is a filter set for this group
196 if (style && style->filter.set && style->filter.filter) {
198 group->filter = new NR::Filter();
199 group->filter->set_x(style->filter.filter->x);
200 group->filter->set_y(style->filter.filter->y);
201 group->filter->set_width(style->filter.filter->width);
202 group->filter->set_height(style->filter.filter->height);
204 //go through all SP filter primitives
205 for(int i=0; i<style->filter.filter->_primitive_count; i++)
206 {
207 SPFilterPrimitive *primitive = style->filter.filter->_primitives[i];
208 //if primitive is gaussianblur
209 if(SP_IS_GAUSSIANBLUR(primitive))
210 {
211 NR::FilterGaussian * gaussian = (NR::FilterGaussian *) group->filter->add_primitive(NR::NR_FILTER_GAUSSIANBLUR);
212 SPGaussianBlur * spblur = SP_GAUSSIANBLUR(primitive);
213 float num = spblur->stdDeviation.getNumber();
214 if( num>=0.0 )
215 {
216 float optnum = spblur->stdDeviation.getOptNumber();
217 if( optnum>=0.0 )
218 gaussian->set_deviation((double) num, (double) optnum);
219 else
220 gaussian->set_deviation((double) num);
221 }
222 }
223 }
224 }
225 else
226 {
227 //no filter set for this group
228 group->filter = NULL;
229 }
231 if (style && style->enable_background.set
232 && style->enable_background.value == SP_CSS_BACKGROUND_NEW) {
233 group->background_new = true;
234 }
235 }
237 static unsigned int
238 nr_arena_group_render (cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags)
239 {
240 NRArenaGroup *group = NR_ARENA_GROUP (item);
242 unsigned int ret = item->state;
244 /* Just compose children into parent buffer */
245 for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
246 ret = nr_arena_item_invoke_render (ct, child, area, pb, flags);
247 if (ret & NR_ARENA_ITEM_STATE_INVALID) break;
248 }
250 return ret;
251 }
253 static unsigned int
254 nr_arena_group_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
255 {
256 NRArenaGroup *group = NR_ARENA_GROUP (item);
258 unsigned int ret = item->state;
260 /* Just compose children into parent buffer */
261 for (NRArenaItem *child = group->children; child != NULL; child = child->next) {
262 ret = nr_arena_item_invoke_clip (child, area, pb);
263 if (ret & NR_ARENA_ITEM_STATE_INVALID) break;
264 }
266 return ret;
267 }
269 static NRArenaItem *
270 nr_arena_group_pick (NRArenaItem *item, NR::Point p, double delta, unsigned int sticky)
271 {
272 NRArenaGroup *group = NR_ARENA_GROUP (item);
274 for (NRArenaItem *child = group->last; child != NULL; child = child->prev) {
275 NRArenaItem *picked = nr_arena_item_invoke_pick (child, p, delta, sticky);
276 if (picked)
277 return (group->transparent) ? picked : item;
278 }
280 return NULL;
281 }
283 void
284 nr_arena_group_set_transparent (NRArenaGroup *group, unsigned int transparent)
285 {
286 nr_return_if_fail (group != NULL);
287 nr_return_if_fail (NR_IS_ARENA_GROUP (group));
289 group->transparent = transparent;
290 }
292 void nr_arena_group_set_child_transform(NRArenaGroup *group, NR::Matrix const &t)
293 {
294 NRMatrix nt(t);
295 nr_arena_group_set_child_transform(group, &nt);
296 }
298 void nr_arena_group_set_child_transform(NRArenaGroup *group, NRMatrix const *t)
299 {
300 if (!t) t = &NR_MATRIX_IDENTITY;
302 if (!NR_MATRIX_DF_TEST_CLOSE (t, &group->child_transform, NR_EPSILON)) {
303 nr_arena_item_request_render (NR_ARENA_ITEM (group));
304 group->child_transform = *t;
305 nr_arena_item_request_update (NR_ARENA_ITEM (group), NR_ARENA_ITEM_STATE_ALL, TRUE);
306 }
307 }