~ubuntu-branches/debian/experimental/inkscape/experimental

« back to all changes in this revision

Viewing changes to src/display/nr-arena-item.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-09-09 23:29:02 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20080909232902-c50iujhk1w79u8e7
Tags: 0.46-2.1
* Non-maintainer upload.
* Add upstream patch fixing a crash in the open dialog
  in the zh_CN.utf8 locale. Closes: #487623.
  Thanks to Luca Bruno for the patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
#define noNR_ARENA_ITEM_VERBOSE
16
16
#define noNR_ARENA_ITEM_DEBUG_CASCADE
17
17
 
 
18
#include <cstring>
 
19
#include <string>
18
20
 
19
21
#include <libnr/nr-blit.h>
20
22
#include <libnr/nr-pixops.h>
21
23
#include "nr-arena.h"
22
24
#include "nr-arena-item.h"
23
 
//#include "nr-arena-group.h"
24
25
#include "gc-core.h"
25
26
 
 
27
#include "nr-filter.h"
 
28
#include "libnr/nr-rect.h"
 
29
#include "nr-arena-group.h"
 
30
#include "prefs-utils.h"
 
31
 
26
32
namespace GC = Inkscape::GC;
27
33
 
28
34
static void nr_arena_item_class_init (NRArenaItemClass *klass);
29
35
static void nr_arena_item_init (NRArenaItem *item);
30
36
static void nr_arena_item_private_finalize (NRObject *object);
31
37
 
32
 
#ifdef arena_item_tile_cache
33
 
bool  insert_cache(NRArenaItem* owner,int th,int tv,NRPixBlock *ipb,NRPixBlock *mpb,double activity,double duration);
34
 
void  remove_caches(NRArenaItem* owner);
35
 
bool  test_cache(NRArenaItem* owner,int th,int tv,NRPixBlock &ipb,NRPixBlock &mpb,bool &hasMask);
36
 
#endif
37
 
 
38
38
static NRObjectClass *parent_class;
39
39
 
40
 
NRType
 
40
NRType 
41
41
nr_arena_item_get_type (void)
42
42
{
43
 
        static NRType type = 0;
44
 
        if (!type) {
45
 
                type = nr_object_register_type (NR_TYPE_OBJECT,
46
 
                                                "NRArenaItem",
47
 
                                                sizeof (NRArenaItemClass),
48
 
                                                sizeof (NRArenaItem),
49
 
                                                (void (*) (NRObjectClass *)) nr_arena_item_class_init,
50
 
                                                (void (*) (NRObject *)) nr_arena_item_init);
51
 
        }
52
 
        return type;
 
43
    static NRType type = 0;
 
44
    if (!type) {
 
45
        type = nr_object_register_type (NR_TYPE_OBJECT,
 
46
                                        "NRArenaItem",
 
47
                                        sizeof (NRArenaItemClass),
 
48
                                        sizeof (NRArenaItem),
 
49
                                        (void (*)(NRObjectClass *))
 
50
                                        nr_arena_item_class_init,
 
51
                                        (void (*)(NRObject *))
 
52
                                        nr_arena_item_init);
 
53
    }
 
54
    return type;
53
55
}
54
56
 
55
57
static void
56
58
nr_arena_item_class_init (NRArenaItemClass *klass)
57
59
{
58
 
        NRObjectClass *object_class;
59
 
 
60
 
        object_class = (NRObjectClass *) klass;
61
 
 
62
 
        parent_class = ((NRObjectClass *) klass)->parent;
63
 
 
64
 
        object_class->finalize = nr_arena_item_private_finalize;
65
 
        object_class->cpp_ctor = NRObject::invoke_ctor<NRArenaItem>;
 
60
    NRObjectClass *object_class;
 
61
 
 
62
    object_class = (NRObjectClass *) klass;
 
63
 
 
64
    parent_class = ((NRObjectClass *) klass)->parent;
 
65
 
 
66
    object_class->finalize = nr_arena_item_private_finalize;
 
67
    object_class->cpp_ctor = NRObject::invoke_ctor < NRArenaItem >;
66
68
}
67
69
 
68
70
static void
69
71
nr_arena_item_init (NRArenaItem *item)
70
72
{
71
 
        item->arena = NULL;
72
 
        item->parent = NULL;
73
 
        item->next = item->prev = NULL;
74
 
 
75
 
        item->key = 0;
76
 
 
77
 
        item->state = 0;
78
 
        item->sensitive = TRUE;
79
 
        item->visible = TRUE;
80
 
 
81
 
        memset(&item->bbox, 0, sizeof(item->bbox));
82
 
        item->transform = NULL;
83
 
        item->opacity = 255;
84
 
        item->render_opacity = FALSE;
85
 
 
86
 
#ifdef arena_item_tile_cache
87
 
  item->activity=0.0;
88
 
  item->skipCaching=false;
89
 
#endif
90
 
 
91
 
        item->transform = NULL;
92
 
        item->clip = NULL;
93
 
        item->mask = NULL;
94
 
        item->px = NULL;
95
 
        item->data = NULL;
 
73
    item->arena = NULL;
 
74
    item->parent = NULL;
 
75
    item->next = item->prev = NULL;
 
76
 
 
77
    item->key = 0;
 
78
 
 
79
    item->state = 0;
 
80
    item->sensitive = TRUE;
 
81
    item->visible = TRUE;
 
82
 
 
83
    memset (&item->bbox, 0, sizeof (item->bbox));
 
84
    item->transform = NULL;
 
85
    item->opacity = 255;
 
86
    item->render_opacity = FALSE;
 
87
 
 
88
    item->transform = NULL;
 
89
    item->clip = NULL;
 
90
    item->mask = NULL;
 
91
    item->px = NULL;
 
92
    item->data = NULL;
 
93
    item->filter = NULL;
 
94
    item->background_pb = NULL;
 
95
    item->background_new = false;
96
96
}
97
97
 
98
98
static void
99
99
nr_arena_item_private_finalize (NRObject *object)
100
100
{
101
 
        NRArenaItem *item=static_cast<NRArenaItem *>(object);
102
 
 
103
 
#ifdef arena_item_tile_cache
104
 
  remove_caches(item);
105
 
#endif
106
 
 
107
 
        item->px = NULL;
108
 
        item->transform = NULL;
109
 
 
110
 
        ((NRObjectClass *) (parent_class))->finalize (object);
 
101
    NRArenaItem *item = static_cast < NRArenaItem * >(object);
 
102
 
 
103
    item->px = NULL;
 
104
    item->transform = NULL;
 
105
 
 
106
    ((NRObjectClass *) (parent_class))->finalize (object);
111
107
}
112
108
 
113
109
NRArenaItem *
114
110
nr_arena_item_children (NRArenaItem *item)
115
111
{
116
 
        nr_return_val_if_fail (item != NULL, NULL);
117
 
        nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
118
 
 
119
 
        if (NR_ARENA_ITEM_VIRTUAL (item, children))
120
 
                return NR_ARENA_ITEM_VIRTUAL (item, children) (item);
121
 
 
122
 
        return NULL;
 
112
    nr_return_val_if_fail (item != NULL, NULL);
 
113
    nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
 
114
 
 
115
    if (NR_ARENA_ITEM_VIRTUAL (item, children))
 
116
        return NR_ARENA_ITEM_VIRTUAL (item, children) (item);
 
117
 
 
118
    return NULL;
123
119
}
124
120
 
125
121
NRArenaItem *
126
122
nr_arena_item_last_child (NRArenaItem *item)
127
123
{
128
 
        nr_return_val_if_fail (item != NULL, NULL);
129
 
        nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
 
124
    nr_return_val_if_fail (item != NULL, NULL);
 
125
    nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
130
126
 
131
 
        if (NR_ARENA_ITEM_VIRTUAL (item, last_child)) {
132
 
                return NR_ARENA_ITEM_VIRTUAL (item, last_child) (item);
133
 
        } else {
134
 
                NRArenaItem *ref;
135
 
                ref = nr_arena_item_children (item);
136
 
                if (ref) while (ref->next) ref = ref->next;
137
 
                return ref;
138
 
        }
 
127
    if (NR_ARENA_ITEM_VIRTUAL (item, last_child)) {
 
128
        return NR_ARENA_ITEM_VIRTUAL (item, last_child) (item);
 
129
    } else {
 
130
        NRArenaItem *ref = nr_arena_item_children (item);
 
131
        if (ref)
 
132
            while (ref->next)
 
133
                ref = ref->next;
 
134
        return ref;
 
135
    }
139
136
}
140
137
 
141
138
void
142
 
nr_arena_item_add_child (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref)
 
139
nr_arena_item_add_child (NRArenaItem *item, NRArenaItem *child,
 
140
                         NRArenaItem *ref)
143
141
{
144
 
        nr_return_if_fail (item != NULL);
145
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
146
 
        nr_return_if_fail (child != NULL);
147
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (child));
148
 
        nr_return_if_fail (child->parent == NULL);
149
 
        nr_return_if_fail (child->prev == NULL);
150
 
        nr_return_if_fail (child->next == NULL);
151
 
        nr_return_if_fail (child->arena == item->arena);
152
 
        nr_return_if_fail (child != ref);
153
 
        nr_return_if_fail (!ref || NR_IS_ARENA_ITEM (ref));
154
 
        nr_return_if_fail (!ref || (ref->parent == item));
 
142
    nr_return_if_fail (item != NULL);
 
143
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
144
    nr_return_if_fail (child != NULL);
 
145
    nr_return_if_fail (NR_IS_ARENA_ITEM (child));
 
146
    nr_return_if_fail (child->parent == NULL);
 
147
    nr_return_if_fail (child->prev == NULL);
 
148
    nr_return_if_fail (child->next == NULL);
 
149
    nr_return_if_fail (child->arena == item->arena);
 
150
    nr_return_if_fail (child != ref);
 
151
    nr_return_if_fail (!ref || NR_IS_ARENA_ITEM (ref));
 
152
    nr_return_if_fail (!ref || (ref->parent == item));
155
153
 
156
 
        if (NR_ARENA_ITEM_VIRTUAL (item, add_child))
157
 
                NR_ARENA_ITEM_VIRTUAL (item, add_child) (item, child, ref);
 
154
    if (NR_ARENA_ITEM_VIRTUAL (item, add_child))
 
155
        NR_ARENA_ITEM_VIRTUAL (item, add_child) (item, child, ref);
158
156
}
159
157
 
160
158
void
161
159
nr_arena_item_remove_child (NRArenaItem *item, NRArenaItem *child)
162
160
{
163
 
        nr_return_if_fail (item != NULL);
164
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
165
 
        nr_return_if_fail (child != NULL);
166
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (child));
167
 
        nr_return_if_fail (child->parent == item);
 
161
    nr_return_if_fail (item != NULL);
 
162
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
163
    nr_return_if_fail (child != NULL);
 
164
    nr_return_if_fail (NR_IS_ARENA_ITEM (child));
 
165
    nr_return_if_fail (child->parent == item);
168
166
 
169
 
        if (NR_ARENA_ITEM_VIRTUAL (item, remove_child))
170
 
                NR_ARENA_ITEM_VIRTUAL (item, remove_child) (item, child);
 
167
    if (NR_ARENA_ITEM_VIRTUAL (item, remove_child))
 
168
        NR_ARENA_ITEM_VIRTUAL (item, remove_child) (item, child);
171
169
}
172
170
 
173
171
void
174
 
nr_arena_item_set_child_position (NRArenaItem *item, NRArenaItem *child, NRArenaItem *ref)
 
172
nr_arena_item_set_child_position (NRArenaItem *item, NRArenaItem *child,
 
173
                                  NRArenaItem *ref)
175
174
{
176
 
        nr_return_if_fail (item != NULL);
177
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
178
 
        nr_return_if_fail (child != NULL);
179
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (child));
180
 
        nr_return_if_fail (child->parent == item);
181
 
        nr_return_if_fail (!ref || NR_IS_ARENA_ITEM (ref));
182
 
        nr_return_if_fail (!ref || (ref->parent == item));
 
175
    nr_return_if_fail (item != NULL);
 
176
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
177
    nr_return_if_fail (child != NULL);
 
178
    nr_return_if_fail (NR_IS_ARENA_ITEM (child));
 
179
    nr_return_if_fail (child->parent == item);
 
180
    nr_return_if_fail (!ref || NR_IS_ARENA_ITEM (ref));
 
181
    nr_return_if_fail (!ref || (ref->parent == item));
183
182
 
184
 
        if (NR_ARENA_ITEM_VIRTUAL (item, set_child_position))
185
 
                NR_ARENA_ITEM_VIRTUAL (item, set_child_position) (item, child, ref);
 
183
    if (NR_ARENA_ITEM_VIRTUAL (item, set_child_position))
 
184
        NR_ARENA_ITEM_VIRTUAL (item, set_child_position) (item, child, ref);
186
185
}
187
186
 
188
187
NRArenaItem *
189
188
nr_arena_item_ref (NRArenaItem *item)
190
189
{
191
 
        nr_object_ref ((NRObject *) item);
 
190
    nr_object_ref ((NRObject *) item);
192
191
 
193
 
        return item;
 
192
    return item;
194
193
}
195
194
 
196
195
NRArenaItem *
197
196
nr_arena_item_unref (NRArenaItem *item)
198
197
{
199
 
        nr_object_unref ((NRObject *) item);
 
198
    nr_object_unref ((NRObject *) item);
200
199
 
201
 
        return NULL;
 
200
    return NULL;
202
201
}
203
202
 
204
203
unsigned int
205
 
nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset)
 
204
nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
 
205
                             unsigned int state, unsigned int reset)
206
206
{
207
 
        NRGC childgc(gc);
 
207
    NRGC childgc (gc);
208
208
 
209
 
        nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
210
 
        nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NR_ARENA_ITEM_STATE_INVALID);
211
 
        nr_return_val_if_fail (!(state & NR_ARENA_ITEM_STATE_INVALID), NR_ARENA_ITEM_STATE_INVALID);
 
209
    nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
 
210
    nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
 
211
                           NR_ARENA_ITEM_STATE_INVALID);
 
212
    nr_return_val_if_fail (!(state & NR_ARENA_ITEM_STATE_INVALID),
 
213
                           NR_ARENA_ITEM_STATE_INVALID);
212
214
 
213
215
#ifdef NR_ARENA_ITEM_DEBUG_CASCADE
214
 
        printf ("Update %s:%p %x %x %x\n", nr_type_name_from_instance ((GTypeInstance *) item), item, state, item->state, reset);
215
 
#endif
216
 
 
217
 
        /* return if in error */
218
 
        if (item->state & NR_ARENA_ITEM_STATE_INVALID) return item->state;
219
 
        /* Set reset flags according to propagation status */
220
 
        if (item->propagate) {
221
 
                reset |= ~item->state;
222
 
                item->propagate = FALSE;
223
 
        }
224
 
        /* Reset our state */
225
 
        item->state &= ~reset;
226
 
        /* Return if NOP */
227
 
        if (!(~item->state & state)) return item->state;
228
 
        /* Test whether to return immediately */
229
 
        if (area && (item->state & NR_ARENA_ITEM_STATE_BBOX)) {
230
 
                if (!nr_rect_l_test_intersect (area, &item->bbox)) return item->state;
231
 
        }
232
 
 
233
 
        /* Reset image cache, if not to be kept */
234
 
        if (!(item->state & NR_ARENA_ITEM_STATE_IMAGE) && (item->px)) {
235
 
                item->px = NULL;
236
 
        }
237
 
#ifdef arena_item_tile_cache
238
 
  remove_caches(item);
239
 
#endif
240
 
 
241
 
        /* Set up local gc */
242
 
        childgc = *gc;
243
 
        if (item->transform) {
244
 
                nr_matrix_multiply (&childgc.transform, item->transform, &childgc.transform);
245
 
        }
246
 
 
247
 
        /* Invoke the real method */
248
 
        item->state = NR_ARENA_ITEM_VIRTUAL (item, update) (item, area, &childgc, state, reset);
249
 
        if (item->state & NR_ARENA_ITEM_STATE_INVALID) return item->state;
250
 
        /* Clipping */
251
 
        if (item->clip) {
252
 
                unsigned int newstate;
253
 
                newstate = nr_arena_item_invoke_update (item->clip, area, &childgc, state, reset);
254
 
                if (newstate & NR_ARENA_ITEM_STATE_INVALID) {
255
 
                        item->state |= NR_ARENA_ITEM_STATE_INVALID;
256
 
                        return item->state;
257
 
                }
258
 
                nr_rect_l_intersect (&item->bbox, &item->bbox, &item->clip->bbox);
259
 
        }
260
 
        /* Masking */
261
 
        if (item->mask) {
262
 
                unsigned int newstate;
263
 
                newstate = nr_arena_item_invoke_update (item->mask, area, &childgc, state, reset);
264
 
                if (newstate & NR_ARENA_ITEM_STATE_INVALID) {
265
 
                        item->state |= NR_ARENA_ITEM_STATE_INVALID;
266
 
                        return item->state;
267
 
                }
268
 
                nr_rect_l_intersect (&item->bbox, &item->bbox, &item->mask->bbox);
269
 
        }
270
 
 
271
 
        return item->state;
 
216
    printf ("Update %s:%p %x %x %x\n",
 
217
            nr_type_name_from_instance ((GTypeInstance *) item), item, state,
 
218
            item->state, reset);
 
219
#endif
 
220
 
 
221
    /* return if in error */
 
222
    if (item->state & NR_ARENA_ITEM_STATE_INVALID)
 
223
        return item->state;
 
224
    /* Set reset flags according to propagation status */
 
225
    if (item->propagate) {
 
226
        reset |= ~item->state;
 
227
        item->propagate = FALSE;
 
228
    }
 
229
    /* Reset our state */
 
230
    item->state &= ~reset;
 
231
    /* Return if NOP */
 
232
    if (!(~item->state & state))
 
233
        return item->state;
 
234
    /* Test whether to return immediately */
 
235
    if (area && (item->state & NR_ARENA_ITEM_STATE_BBOX)) {
 
236
        if (!nr_rect_l_test_intersect (area, &item->bbox))
 
237
            return item->state;
 
238
    }
 
239
 
 
240
    /* Reset image cache, if not to be kept */
 
241
    if (!(item->state & NR_ARENA_ITEM_STATE_IMAGE) && (item->px)) {
 
242
        item->px = NULL;
 
243
    }
 
244
 
 
245
    /* Set up local gc */
 
246
    childgc = *gc;
 
247
    if (item->transform) {
 
248
        nr_matrix_multiply (&childgc.transform, item->transform,
 
249
                            &childgc.transform);
 
250
    }
 
251
    /* Remember the transformation matrix */
 
252
    item->ctm = childgc.transform;
 
253
 
 
254
    /* Invoke the real method */
 
255
    item->state =
 
256
        NR_ARENA_ITEM_VIRTUAL (item, update) (item, area, &childgc, state,
 
257
                                              reset);
 
258
    if (item->state & NR_ARENA_ITEM_STATE_INVALID)
 
259
        return item->state;
 
260
    /* Enlarge the bounding box to contain filter effects */
 
261
    if (item->filter) {
 
262
        item->filter->bbox_enlarge (item->bbox);
 
263
    }
 
264
    // fixme: to fix the display glitches, in outline mode bbox must be a combination of 
 
265
    // full item bbox and its clip and mask (after we have the API to get these)
 
266
 
 
267
    /* Clipping */
 
268
    if (item->clip) {
 
269
        // FIXME: since here we only need bbox, consider passing 
 
270
        // ((state & !(NR_ARENA_ITEM_STATE_RENDER)) | NR_ARENA_ITEM_STATE_BBOX)
 
271
        // instead of state, so it does not have to create rendering structures in nr_arena_shape_update
 
272
        unsigned int newstate = nr_arena_item_invoke_update (item->clip, area, &childgc, state, reset); 
 
273
        if (newstate & NR_ARENA_ITEM_STATE_INVALID) {
 
274
            item->state |= NR_ARENA_ITEM_STATE_INVALID;
 
275
            return item->state;
 
276
        }
 
277
        nr_rect_l_intersect (&item->bbox, &item->bbox, &item->clip->bbox);
 
278
    }
 
279
    /* Masking */
 
280
    if (item->mask) {
 
281
        unsigned int newstate = nr_arena_item_invoke_update (item->mask, area, &childgc, state, reset);
 
282
        if (newstate & NR_ARENA_ITEM_STATE_INVALID) {
 
283
            item->state |= NR_ARENA_ITEM_STATE_INVALID;
 
284
            return item->state;
 
285
        }
 
286
        nr_rect_l_intersect (&item->bbox, &item->bbox, &item->mask->bbox);
 
287
    }
 
288
 
 
289
    return item->state;
272
290
}
273
291
 
274
292
/**
277
295
 *    \return Has NR_ARENA_ITEM_STATE_RENDER set on success.
278
296
 */
279
297
 
280
 
unsigned int nr_arena_item_invoke_render(NRArenaItem *item, NRRectL const *area, NRPixBlock *pb, unsigned int flags)
 
298
unsigned int
 
299
nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area,
 
300
                             NRPixBlock *pb, unsigned int flags)
281
301
{
282
 
        NRRectL carea;
283
 
        NRPixBlock *dpb;
284
 
        NRPixBlock cpb;
285
 
        unsigned int state;
 
302
   bool outline = (item->arena->rendermode == RENDERMODE_OUTLINE);
286
303
 
287
 
        nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
288
 
        nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NR_ARENA_ITEM_STATE_INVALID);
289
 
        nr_return_val_if_fail (item->state & NR_ARENA_ITEM_STATE_BBOX, item->state);
 
304
    nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
 
305
    nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
 
306
                           NR_ARENA_ITEM_STATE_INVALID);
 
307
    nr_return_val_if_fail (item->state & NR_ARENA_ITEM_STATE_BBOX,
 
308
                           item->state);
290
309
 
291
310
#ifdef NR_ARENA_ITEM_VERBOSE
292
 
        printf ("Invoke render %p: %d %d - %d %d\n", item, area->x0, area->y0, area->x1, area->y1);
293
 
#endif
294
 
 
295
 
#ifdef arena_item_tile_cache
296
 
  item->activity*=0.5;
297
 
#endif
298
 
 
299
 
        /* If we are outside bbox just return successfully */
300
 
        if (!item->visible) return item->state | NR_ARENA_ITEM_STATE_RENDER;
301
 
        nr_rect_l_intersect (&carea, area, &item->bbox);
302
 
        if (nr_rect_l_test_empty (&carea)) return item->state | NR_ARENA_ITEM_STATE_RENDER;
303
 
 
304
 
        if (item->px) {
305
 
                /* Has cache pixblock, render this and return */
306
 
                nr_pixblock_setup_extern (&cpb, NR_PIXBLOCK_MODE_R8G8B8A8P,
307
 
                                          /* fixme: This probably cannot overflow, because we render only if visible */
308
 
                                          /* fixme: and pixel cache is there only for small items */
309
 
                                          /* fixme: But this still needs extra check (Lauris) */
310
 
                                          item->bbox.x0, item->bbox.y0,
311
 
                                          item->bbox.x1, item->bbox.y1,
312
 
                                          item->px, 4 * (item->bbox.x1 - item->bbox.x0), FALSE, FALSE);
313
 
                nr_blit_pixblock_pixblock (pb, &cpb);
314
 
                nr_pixblock_release (&cpb);
315
 
                pb->empty = FALSE;
316
 
                return item->state | NR_ARENA_ITEM_STATE_RENDER;
317
 
        }
318
 
 
319
 
        dpb = pb;
320
 
  bool  canCache=false;
321
 
#ifdef arena_item_tile_cache  
322
 
  bool checkCache=false;
323
 
  int   tile_h=0,tile_v=0;
324
 
#endif  
325
 
        /* Setup cache if we can */
326
 
        if ((!(flags & NR_ARENA_ITEM_RENDER_NO_CACHE)) &&
327
 
            (carea.x0 <= item->bbox.x0) && (carea.y0 <= item->bbox.y0) &&
328
 
            (carea.x1 >= item->bbox.x1) && (carea.y1 >= item->bbox.y1) &&
329
 
            (((item->bbox.x1 - item->bbox.x0) * (item->bbox.y1 - item->bbox.y0)) <= 4096)) {
330
 
                // Item bbox is fully in renderable area and size is acceptable
331
 
                carea.x0 = item->bbox.x0;
332
 
                carea.y0 = item->bbox.y0;
333
 
                carea.x1 = item->bbox.x1;
334
 
                carea.y1 = item->bbox.y1;
335
 
                item->px = new (GC::ATOMIC) unsigned char[4 * (carea.x1 - carea.x0) * (carea.y1 - carea.y0)];
336
 
                nr_pixblock_setup_extern (&cpb, NR_PIXBLOCK_MODE_R8G8B8A8P,
337
 
                              carea.x0, carea.y0, carea.x1, carea.y1,
338
 
                              item->px, 4 * (carea.x1 - carea.x0), TRUE, TRUE);
339
 
        cpb.visible_area = pb->visible_area; 
340
 
                dpb = &cpb;
341
 
                // Set nocache flag for downstream rendering
342
 
                flags |= NR_ARENA_ITEM_RENDER_NO_CACHE;
343
 
        } else {
344
 
#ifdef arena_item_tile_cache
345
 
    if ( item->skipCaching ) {
346
 
    } else {
347
 
      int tl=area->x0&(~127);
348
 
      int tt=area->y0&(~127);
349
 
      if ( area->x1 <= tl+128 && area->y1 <= tt+128 ) {
350
 
        checkCache=true;
351
 
        tile_h=tl/128;
352
 
        tile_v=tt/128;
353
 
        int surf=(area->x1-area->x0)*(area->y1-area->y0);
354
 
        if ( surf >= 4096 ) {
355
 
          canCache=true;
356
 
          carea.x0=tl;
357
 
          carea.y0=tt;
358
 
          carea.x1=tl+128;
359
 
          carea.y1=tt+128;
360
 
        }
361
 
      }
362
 
    }
363
 
#endif
364
 
  }
365
 
 
366
 
#ifdef arena_item_tile_cache
367
 
  item->activity+=1.0;
368
 
#endif
369
 
 
370
 
#ifdef arena_item_tile_cache
371
 
  if ( checkCache ) {
372
 
    NRPixBlock ipb, mpb;
373
 
    bool       hasMask;
374
 
    if ( test_cache(item,tile_h,tile_v,ipb,mpb,hasMask) ) {
375
 
      // youpi! c'etait deja cache
376
 
      if ( hasMask ) {
377
 
        nr_blit_pixblock_pixblock_mask (dpb, &ipb, &mpb);
378
 
      } else if ( ((item->opacity != 255) && !item->render_opacity) ) {
379
 
        nr_blit_pixblock_pixblock_alpha (dpb, &ipb, item->opacity);
380
 
      } else {
381
 
        nr_blit_pixblock_pixblock (pb, &ipb);
382
 
      }
383
 
      pb->empty = FALSE;
384
 
      return item->state | NR_ARENA_ITEM_STATE_RENDER;
385
 
    }
386
 
  }
387
 
#endif
388
 
  if ( canCache ) {
389
 
#ifdef arena_item_tile_cache
390
 
    // nota: exclusif de dpb != pb, donc pas de cas particulier a la fin
391
 
    NRPixBlock ipb, mpb;
392
 
 
393
 
    // struct timeval start_time,end_time;
394
 
    // gettimeofday(&start_time,NULL);
395
 
    GTimeVal start_time,end_time;
396
 
    g_get_current_time (&start_time);
397
 
    int    duration=0;
398
 
 
399
 
    /* Setup and render item buffer */
400
 
    nr_pixblock_setup_fast (&ipb, NR_PIXBLOCK_MODE_R8G8B8A8P, carea.x0, carea.y0, carea.x1, carea.y1, TRUE);
401
 
    ipb.visible_area = pb->visible_area; 
402
 
    state = NR_ARENA_ITEM_VIRTUAL (item, render) (item, &carea, &ipb, flags);
403
 
    if (state & NR_ARENA_ITEM_STATE_INVALID) {
404
 
      /* Clean up and return error */
405
 
      nr_pixblock_release (&ipb);
406
 
      if (dpb != pb) nr_pixblock_release (dpb);
407
 
      item->state |= NR_ARENA_ITEM_STATE_INVALID;
408
 
      return item->state;
409
 
    }
410
 
    ipb.empty = FALSE;
411
 
 
412
 
    if (item->clip || item->mask) {
413
 
      /* Setup mask pixblock */
414
 
      nr_pixblock_setup_fast (&mpb, NR_PIXBLOCK_MODE_A8, carea.x0, carea.y0, carea.x1, carea.y1, TRUE);
415
 
      mpb.visible_area = pb->visible_area; 
416
 
      /* Do clip if needed */
417
 
      if (item->clip) {
418
 
        state = nr_arena_item_invoke_clip (item->clip, &carea, &mpb);
419
 
        if (state & NR_ARENA_ITEM_STATE_INVALID) {
420
 
          /* Clean up and return error */
421
 
          nr_pixblock_release (&mpb);
422
 
          nr_pixblock_release (&ipb);
423
 
          if (dpb != pb) nr_pixblock_release (dpb);
424
 
          item->state |= NR_ARENA_ITEM_STATE_INVALID;
425
 
          return item->state;
426
 
        }
427
 
        mpb.empty = FALSE;
428
 
      }
429
 
      /* Do mask if needed */
430
 
      if (item->mask) {
431
 
        NRPixBlock tpb;
432
 
        /* Set up yet another temporary pixblock */
433
 
        nr_pixblock_setup_fast (&tpb, NR_PIXBLOCK_MODE_R8G8B8A8N, carea.x0, carea.y0, carea.x1, carea.y1, TRUE);
434
 
        tpb.visible_area = pb->visible_area; 
435
 
        state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (item->mask, &carea, &tpb, flags);
436
 
        if (state & NR_ARENA_ITEM_STATE_INVALID) {
437
 
          /* Clean up and return error */
438
 
          nr_pixblock_release (&tpb);
439
 
          nr_pixblock_release (&mpb);
440
 
          nr_pixblock_release (&ipb);
441
 
          if (dpb != pb) nr_pixblock_release (dpb);
442
 
          item->state |= NR_ARENA_ITEM_STATE_INVALID;
443
 
          return item->state;
444
 
        }
445
 
        /* Composite with clip */
446
 
        if (item->clip) {
447
 
          int x, y;
448
 
          for (y = carea.y0; y < carea.y1; y++) {
449
 
            unsigned char *s, *d;
450
 
            s = NR_PIXBLOCK_PX (&tpb) + (y - carea.y0) * tpb.rs;
451
 
            d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs;
452
 
            for (x = carea.x0; x < carea.x1; x++) {
453
 
              unsigned int m;
454
 
              m = ((s[0] + s[1] + s[2]) * s[3] + 127) / (3 * 255);
455
 
              d[0] = NR_PREMUL (d[0], m);
456
 
              s += 4;
457
 
              d += 1;
458
 
            }
459
 
          }
460
 
        } else {
461
 
          int x, y;
462
 
          for (y = carea.y0; y < carea.y1; y++) {
463
 
            unsigned char *s, *d;
464
 
            s = NR_PIXBLOCK_PX (&tpb) + (y - carea.y0) * tpb.rs;
465
 
            d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs;
466
 
            for (x = carea.x0; x < carea.x1; x++) {
467
 
              unsigned int m;
468
 
              m = ((s[0] + s[1] + s[2]) * s[3] + 127) / (3 * 255);
469
 
              d[0] = m;
470
 
              s += 4;
471
 
              d += 1;
472
 
            }
473
 
          }
474
 
          mpb.empty = FALSE;
475
 
        }
476
 
        nr_pixblock_release (&tpb);
477
 
      }
478
 
      /* Multiply with opacity if needed */
479
 
      if ((item->opacity != 255) && !item->render_opacity && item->arena->rendermode != RENDERMODE_OUTLINE) {
480
 
        int x, y;
481
 
        unsigned int a;
482
 
        a = item->opacity;
483
 
        for (y = carea.y0; y < carea.y1; y++) {
484
 
          unsigned char *d;
485
 
          d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs;
486
 
          for (x = carea.x0; x < carea.x1; x++) {
487
 
            d[0] = NR_PREMUL (d[0], a);
488
 
            d += 1;
489
 
          }
490
 
        }
491
 
      }
492
 
      /* Compose rendering pixblock int destination */
493
 
      // gettimeofday(&end_time,NULL);
494
 
      g_get_current_time (&end_time);
495
 
      duration=(end_time.tv_sec-start_time.tv_sec)*1000+(end_time.tv_usec-start_time.tv_usec)/1000;
496
 
      if ( !(ipb.empty) ) {
497
 
        nr_blit_pixblock_pixblock_mask (dpb, &ipb, &mpb);
498
 
        if ( insert_cache(item,tile_h,tile_v,&ipb,&mpb,item->activity,(double)duration) ) {
499
 
        } else {
500
 
          nr_pixblock_release (&mpb);
501
 
          nr_pixblock_release (&ipb);
502
 
        }
503
 
        dpb->empty = FALSE;
504
 
      } else {
505
 
        nr_pixblock_release (&ipb);
506
 
      }
507
 
    } else if ( ((item->opacity != 255) && !item->render_opacity && item->arena->rendermode != RENDERMODE_OUTLINE) ) {
508
 
      /* Opacity only */
509
 
      // gettimeofday(&end_time,NULL);
510
 
      g_get_current_time (&end_time);
511
 
      duration=(end_time.tv_sec-start_time.tv_sec)*1000+(end_time.tv_usec-start_time.tv_usec)/1000;
512
 
      if ( !(ipb.empty) ) {
513
 
        nr_blit_pixblock_pixblock_alpha (dpb, &ipb, item->opacity);
514
 
        if ( insert_cache(item,tile_h,tile_v,&ipb,NULL,item->activity,(double)duration) ) {
515
 
        } else {
516
 
          nr_pixblock_release (&ipb);
517
 
        }
518
 
        dpb->empty = FALSE;
519
 
      } else {
520
 
        nr_pixblock_release (&ipb);
521
 
      }
522
 
    } else {
523
 
      // gettimeofday(&end_time,NULL);
524
 
      g_get_current_time (&end_time);
525
 
      duration=(end_time.tv_sec-start_time.tv_sec)*1000+(end_time.tv_usec-start_time.tv_usec)/1000;
526
 
      if ( !(ipb.empty) ) {
527
 
        nr_blit_pixblock_pixblock (dpb, &ipb);
528
 
        if ( insert_cache(item,tile_h,tile_v,&ipb,NULL,item->activity,(double)duration) ) {
529
 
        } else {
530
 
          nr_pixblock_release (&ipb);
531
 
        }
532
 
        dpb->empty = FALSE;
533
 
      } else {
534
 
        nr_pixblock_release (&ipb);
535
 
      }
536
 
    }
537
 
#endif
538
 
  } else {
 
311
    printf ("Invoke render %p: %d %d - %d %d\n", item, area->x0, area->y0,
 
312
            area->x1, area->y1);
 
313
#endif
 
314
 
 
315
    /* If we are outside bbox just return successfully */
 
316
    if (!item->visible)
 
317
        return item->state | NR_ARENA_ITEM_STATE_RENDER;
 
318
 
 
319
    NRRectL carea;
 
320
    nr_rect_l_intersect (&carea, area, &item->bbox);
 
321
    if (nr_rect_l_test_empty (&carea))
 
322
        return item->state | NR_ARENA_ITEM_STATE_RENDER;
 
323
    if (item->filter && !outline) {
 
324
        item->filter->area_enlarge (carea, item->ctm);
 
325
        nr_rect_l_intersect (&carea, &carea, &item->bbox);
 
326
    }
 
327
 
 
328
    if (outline) {
 
329
    // No caching in outline mode for now; investigate if it really gives any advantage with cairo.
 
330
    // Also no attempts to clip anything; just render everything: item, clip, mask   
 
331
            // First, render the object itself 
 
332
            unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags);
 
333
            if (state & NR_ARENA_ITEM_STATE_INVALID) {
 
334
                /* Clean up and return error */
 
335
                item->state |= NR_ARENA_ITEM_STATE_INVALID;
 
336
                return item->state;
 
337
            }
 
338
 
 
339
            // render clip and mask, if any
 
340
            guint32 saved_rgba = item->arena->outlinecolor; // save current outline color
 
341
            // render clippath as an object, using a different color
 
342
            if (item->clip) {
 
343
                item->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "clips", 0x00ff00ff); // green clips
 
344
                NR_ARENA_ITEM_VIRTUAL (item->clip, render) (ct, item->clip, &carea, pb, flags);
 
345
            } 
 
346
            // render mask as an object, using a different color
 
347
            if (item->mask) {
 
348
                item->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "masks", 0x0000ffff); // blue masks
 
349
                NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, &carea, pb, flags);
 
350
            }
 
351
            item->arena->outlinecolor = saved_rgba; // restore outline color
 
352
 
 
353
            return item->state | NR_ARENA_ITEM_STATE_RENDER;
 
354
    }
 
355
 
 
356
    NRPixBlock cpb;
 
357
    if (item->px) {
 
358
        /* Has cache pixblock, render this and return */
 
359
        nr_pixblock_setup_extern (&cpb, NR_PIXBLOCK_MODE_R8G8B8A8P,
 
360
                                  /* fixme: This probably cannot overflow, because we render only if visible */
 
361
                                  /* fixme: and pixel cache is there only for small items */
 
362
                                  /* fixme: But this still needs extra check (Lauris) */
 
363
                                  item->bbox.x0, item->bbox.y0,
 
364
                                  item->bbox.x1, item->bbox.y1,
 
365
                                  item->px,
 
366
                                  4 * (item->bbox.x1 - item->bbox.x0), FALSE,
 
367
                                  FALSE);
 
368
        nr_blit_pixblock_pixblock (pb, &cpb);
 
369
        nr_pixblock_release (&cpb);
 
370
        pb->empty = FALSE;
 
371
        return item->state | NR_ARENA_ITEM_STATE_RENDER;
 
372
    }
 
373
 
 
374
    NRPixBlock *dpb = pb;
 
375
 
 
376
    /* Setup cache if we can */
 
377
    if ((!(flags & NR_ARENA_ITEM_RENDER_NO_CACHE)) &&
 
378
        (carea.x0 <= item->bbox.x0) && (carea.y0 <= item->bbox.y0) &&
 
379
        (carea.x1 >= item->bbox.x1) && (carea.y1 >= item->bbox.y1) &&
 
380
        (((item->bbox.x1 - item->bbox.x0) * (item->bbox.y1 -
 
381
                                             item->bbox.y0)) <= 4096)) {
 
382
        // Item bbox is fully in renderable area and size is acceptable
 
383
        carea.x0 = item->bbox.x0;
 
384
        carea.y0 = item->bbox.y0;
 
385
        carea.x1 = item->bbox.x1;
 
386
        carea.y1 = item->bbox.y1;
 
387
        item->px =
 
388
            new (GC::ATOMIC) unsigned char[4 * (carea.x1 - carea.x0) *
 
389
                                           (carea.y1 - carea.y0)];
 
390
        nr_pixblock_setup_extern (&cpb, NR_PIXBLOCK_MODE_R8G8B8A8P, carea.x0,
 
391
                                  carea.y0, carea.x1, carea.y1, item->px,
 
392
                                  4 * (carea.x1 - carea.x0), TRUE, TRUE);
 
393
        cpb.visible_area = pb->visible_area;
 
394
        dpb = &cpb;
 
395
        // Set nocache flag for downstream rendering
 
396
        flags |= NR_ARENA_ITEM_RENDER_NO_CACHE;
 
397
    }
 
398
 
539
399
    /* Determine, whether we need temporary buffer */
540
 
    if (item->clip || item->mask || ((item->opacity != 255) && !item->render_opacity && item->arena->rendermode != RENDERMODE_OUTLINE)) {
541
 
      NRPixBlock ipb, mpb;
542
 
 
543
 
      /* Setup and render item buffer */
544
 
      nr_pixblock_setup_fast (&ipb, NR_PIXBLOCK_MODE_R8G8B8A8P, carea.x0, carea.y0, carea.x1, carea.y1, TRUE);
545
 
      ipb.visible_area = pb->visible_area; 
546
 
      state = NR_ARENA_ITEM_VIRTUAL (item, render) (item, &carea, &ipb, flags);
547
 
      if (state & NR_ARENA_ITEM_STATE_INVALID) {
548
 
        /* Clean up and return error */
 
400
    if (item->clip || item->mask
 
401
        || ((item->opacity != 255) && !item->render_opacity)
 
402
        || (item->filter) || item->background_new
 
403
        || (item->parent && item->parent->background_pb)) {
 
404
 
 
405
        /* Setup and render item buffer */
 
406
        NRPixBlock ipb;
 
407
        nr_pixblock_setup_fast (&ipb, NR_PIXBLOCK_MODE_R8G8B8A8P,
 
408
                                carea.x0, carea.y0, carea.x1, carea.y1,
 
409
                                TRUE);
 
410
 
 
411
        //  if memory allocation failed, abort render
 
412
        if (ipb.size != NR_PIXBLOCK_SIZE_TINY && ipb.data.px == NULL) {
 
413
            nr_pixblock_release (&ipb);
 
414
            return (item->state);
 
415
        }
 
416
 
 
417
        /* If background access is used, save the pixblock address.
 
418
         * This address is set to NULL at the end of this block */
 
419
        if (item->background_new ||
 
420
            (item->parent && item->parent->background_pb)) {
 
421
            item->background_pb = &ipb;
 
422
        }
 
423
 
 
424
        ipb.visible_area = pb->visible_area;
 
425
        if (item->filter) {
 
426
              item->filter->area_enlarge (ipb.visible_area, item->ctm);
 
427
        }
 
428
 
 
429
        unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, &ipb, flags);
 
430
        if (state & NR_ARENA_ITEM_STATE_INVALID) {
 
431
            /* Clean up and return error */
 
432
            nr_pixblock_release (&ipb);
 
433
            if (dpb != pb)
 
434
                nr_pixblock_release (dpb);
 
435
            item->state |= NR_ARENA_ITEM_STATE_INVALID;
 
436
            return item->state;
 
437
        }
 
438
        ipb.empty = FALSE;
 
439
 
 
440
        /* Run filtering, if a filter is set for this object */
 
441
        if (item->filter) {
 
442
            item->filter->render (item, &ipb);
 
443
        }
 
444
 
 
445
        if (item->clip || item->mask) {
 
446
            /* Setup mask pixblock */
 
447
            NRPixBlock mpb;
 
448
            nr_pixblock_setup_fast (&mpb, NR_PIXBLOCK_MODE_A8, carea.x0,
 
449
                                    carea.y0, carea.x1, carea.y1, TRUE);
 
450
 
 
451
            if (mpb.data.px != NULL) { // if memory allocation was successful
 
452
 
 
453
                mpb.visible_area = pb->visible_area;
 
454
                /* Do clip if needed */
 
455
                if (item->clip) {
 
456
                    state = nr_arena_item_invoke_clip (item->clip, &carea, &mpb);
 
457
                    if (state & NR_ARENA_ITEM_STATE_INVALID) {
 
458
                        /* Clean up and return error */
 
459
                        nr_pixblock_release (&mpb);
 
460
                        nr_pixblock_release (&ipb);
 
461
                        if (dpb != pb)
 
462
                            nr_pixblock_release (dpb);
 
463
                        item->state |= NR_ARENA_ITEM_STATE_INVALID;
 
464
                        return item->state;
 
465
                    }
 
466
                    mpb.empty = FALSE;
 
467
                }
 
468
                /* Do mask if needed */
 
469
                if (item->mask) {
 
470
                    NRPixBlock tpb;
 
471
                    /* Set up yet another temporary pixblock */
 
472
                    nr_pixblock_setup_fast (&tpb, NR_PIXBLOCK_MODE_R8G8B8A8N,
 
473
                                            carea.x0, carea.y0, carea.x1,
 
474
                                            carea.y1, TRUE);
 
475
 
 
476
                    if (tpb.data.px != NULL) { // if memory allocation was successful
 
477
 
 
478
                        tpb.visible_area = pb->visible_area;
 
479
                        unsigned int state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, &carea, &tpb, flags);
 
480
                        if (state & NR_ARENA_ITEM_STATE_INVALID) {
 
481
                            /* Clean up and return error */
 
482
                            nr_pixblock_release (&tpb);
 
483
                            nr_pixblock_release (&mpb);
 
484
                            nr_pixblock_release (&ipb);
 
485
                            if (dpb != pb)
 
486
                                nr_pixblock_release (dpb);
 
487
                            item->state |= NR_ARENA_ITEM_STATE_INVALID;
 
488
                            return item->state;
 
489
                        }
 
490
                        /* Composite with clip */
 
491
                        if (item->clip) {
 
492
                            int x, y;
 
493
                            for (y = carea.y0; y < carea.y1; y++) {
 
494
                                unsigned char *s, *d;
 
495
                                s = NR_PIXBLOCK_PX (&tpb) + (y -
 
496
                                                             carea.y0) * tpb.rs;
 
497
                                d = NR_PIXBLOCK_PX (&mpb) + (y -
 
498
                                                             carea.y0) * mpb.rs;
 
499
                                for (x = carea.x0; x < carea.x1; x++) {
 
500
                                    unsigned int m;
 
501
                                    m = NR_PREMUL_112 (s[0] + s[1] + s[2], s[3]);
 
502
                                    d[0] =
 
503
                                        FAST_DIV_ROUND < 3 * 255 * 255 >
 
504
                                        (NR_PREMUL_123 (d[0], m));
 
505
                                    s += 4;
 
506
                                    d += 1;
 
507
                                }
 
508
                            }
 
509
                        } else {
 
510
                            int x, y;
 
511
                            for (y = carea.y0; y < carea.y1; y++) {
 
512
                                unsigned char *s, *d;
 
513
                                s = NR_PIXBLOCK_PX (&tpb) + (y -
 
514
                                                             carea.y0) * tpb.rs;
 
515
                                d = NR_PIXBLOCK_PX (&mpb) + (y -
 
516
                                                             carea.y0) * mpb.rs;
 
517
                                for (x = carea.x0; x < carea.x1; x++) {
 
518
                                    unsigned int m;
 
519
                                    m = NR_PREMUL_112 (s[0] + s[1] + s[2], s[3]);
 
520
                                    d[0] = FAST_DIV_ROUND < 3 * 255 > (m);
 
521
                                    s += 4;
 
522
                                    d += 1;
 
523
                                }
 
524
                            }
 
525
                            mpb.empty = FALSE;
 
526
                        }
 
527
                    }
 
528
                    nr_pixblock_release (&tpb);
 
529
                }
 
530
                /* Multiply with opacity if needed */
 
531
                if ((item->opacity != 255) && !item->render_opacity
 
532
                    ) {
 
533
                    int x, y;
 
534
                    unsigned int a;
 
535
                    a = item->opacity;
 
536
                    for (y = carea.y0; y < carea.y1; y++) {
 
537
                        unsigned char *d;
 
538
                        d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs;
 
539
                        for (x = carea.x0; x < carea.x1; x++) {
 
540
                            d[0] = NR_PREMUL_111 (d[0], a);
 
541
                            d += 1;
 
542
                        }
 
543
                    }
 
544
                }
 
545
                /* Compose rendering pixblock int destination */
 
546
                nr_blit_pixblock_pixblock_mask (dpb, &ipb, &mpb);
 
547
            }
 
548
            nr_pixblock_release (&mpb);
 
549
        } else {
 
550
            if (item->render_opacity) { // opacity was already rendered in, just copy to dpb here
 
551
                nr_blit_pixblock_pixblock(dpb, &ipb);
 
552
            } else { // copy while multiplying by opacity
 
553
                nr_blit_pixblock_pixblock_alpha (dpb, &ipb, item->opacity);
 
554
            }
 
555
        }
549
556
        nr_pixblock_release (&ipb);
550
 
        if (dpb != pb) nr_pixblock_release (dpb);
551
 
        item->state |= NR_ARENA_ITEM_STATE_INVALID;
552
 
        return item->state;
553
 
      }
554
 
      ipb.empty = FALSE;
555
 
 
556
 
      if (item->clip || item->mask) {
557
 
        /* Setup mask pixblock */
558
 
        nr_pixblock_setup_fast (&mpb, NR_PIXBLOCK_MODE_A8, carea.x0, carea.y0, carea.x1, carea.y1, TRUE);
559
 
        mpb.visible_area = pb->visible_area; 
560
 
        /* Do clip if needed */
561
 
        if (item->clip) {
562
 
          state = nr_arena_item_invoke_clip (item->clip, &carea, &mpb);
563
 
          if (state & NR_ARENA_ITEM_STATE_INVALID) {
564
 
            /* Clean up and return error */
565
 
            nr_pixblock_release (&mpb);
566
 
            nr_pixblock_release (&ipb);
567
 
            if (dpb != pb) nr_pixblock_release (dpb);
568
 
            item->state |= NR_ARENA_ITEM_STATE_INVALID;
569
 
            return item->state;
570
 
          }
571
 
          mpb.empty = FALSE;
572
 
        }
573
 
        /* Do mask if needed */
574
 
        if (item->mask) {
575
 
          NRPixBlock tpb;
576
 
          /* Set up yet another temporary pixblock */
577
 
          nr_pixblock_setup_fast (&tpb, NR_PIXBLOCK_MODE_R8G8B8A8N, carea.x0, carea.y0, carea.x1, carea.y1, TRUE);
578
 
          tpb.visible_area = pb->visible_area; 
579
 
          state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (item->mask, &carea, &tpb, flags);
580
 
          if (state & NR_ARENA_ITEM_STATE_INVALID) {
581
 
            /* Clean up and return error */
582
 
            nr_pixblock_release (&tpb);
583
 
            nr_pixblock_release (&mpb);
584
 
            nr_pixblock_release (&ipb);
585
 
            if (dpb != pb) nr_pixblock_release (dpb);
586
 
            item->state |= NR_ARENA_ITEM_STATE_INVALID;
587
 
            return item->state;
588
 
          }
589
 
          /* Composite with clip */
590
 
          if (item->clip) {
591
 
            int x, y;
592
 
            for (y = carea.y0; y < carea.y1; y++) {
593
 
              unsigned char *s, *d;
594
 
              s = NR_PIXBLOCK_PX (&tpb) + (y - carea.y0) * tpb.rs;
595
 
              d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs;
596
 
              for (x = carea.x0; x < carea.x1; x++) {
597
 
                unsigned int m;
598
 
                m = ((s[0] + s[1] + s[2]) * s[3] + 127) / (3 * 255);
599
 
                d[0] = NR_PREMUL (d[0], m);
600
 
                s += 4;
601
 
                d += 1;
602
 
              }
603
 
            }
604
 
          } else {
605
 
            int x, y;
606
 
            for (y = carea.y0; y < carea.y1; y++) {
607
 
              unsigned char *s, *d;
608
 
              s = NR_PIXBLOCK_PX (&tpb) + (y - carea.y0) * tpb.rs;
609
 
              d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs;
610
 
              for (x = carea.x0; x < carea.x1; x++) {
611
 
                unsigned int m;
612
 
                m = ((s[0] + s[1] + s[2]) * s[3] + 127) / (3 * 255);
613
 
                d[0] = m;
614
 
                s += 4;
615
 
                d += 1;
616
 
              }
617
 
            }
618
 
            mpb.empty = FALSE;
619
 
          }
620
 
          nr_pixblock_release (&tpb);
621
 
        }
622
 
        /* Multiply with opacity if needed */
623
 
        if ((item->opacity != 255) && !item->render_opacity && item->arena->rendermode != RENDERMODE_OUTLINE) {
624
 
          int x, y;
625
 
          unsigned int a;
626
 
          a = item->opacity;
627
 
          for (y = carea.y0; y < carea.y1; y++) {
628
 
            unsigned char *d;
629
 
            d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs;
630
 
            for (x = carea.x0; x < carea.x1; x++) {
631
 
              d[0] = NR_PREMUL (d[0], a);
632
 
              d += 1;
633
 
            }
634
 
          }
635
 
        }
636
 
        /* Compose rendering pixblock int destination */
637
 
        nr_blit_pixblock_pixblock_mask (dpb, &ipb, &mpb);
638
 
        nr_pixblock_release (&mpb);
639
 
      } else {
640
 
        /* Opacity only */
641
 
        nr_blit_pixblock_pixblock_alpha (dpb, &ipb, item->opacity);
642
 
      }
643
 
      nr_pixblock_release (&ipb);
644
 
      dpb->empty = FALSE;
 
557
        dpb->empty = FALSE;
 
558
        /* This pointer wouldn't be valid outside this block, so clear it */
 
559
        item->background_pb = NULL;
645
560
    } else {
646
 
      /* Just render */
647
 
      state = NR_ARENA_ITEM_VIRTUAL (item, render) (item, &carea, dpb, flags);
648
 
      if (state & NR_ARENA_ITEM_STATE_INVALID) {
649
 
        /* Clean up and return error */
650
 
        if (dpb != pb) nr_pixblock_release (dpb);
651
 
        item->state |= NR_ARENA_ITEM_STATE_INVALID;
652
 
        return item->state;
653
 
      }
654
 
      dpb->empty = FALSE;
 
561
        /* Just render */
 
562
        unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, dpb, flags);
 
563
        if (state & NR_ARENA_ITEM_STATE_INVALID) {
 
564
            /* Clean up and return error */
 
565
            if (dpb != pb)
 
566
                nr_pixblock_release (dpb);
 
567
            item->state |= NR_ARENA_ITEM_STATE_INVALID;
 
568
            return item->state;
 
569
        }
 
570
        dpb->empty = FALSE;
655
571
    }
656
572
 
657
573
    if (dpb != pb) {
658
 
      /* Have to blit from cache */
659
 
      nr_blit_pixblock_pixblock (pb, dpb);
660
 
      nr_pixblock_release (dpb);
661
 
      pb->empty = FALSE;
662
 
      item->state |= NR_ARENA_ITEM_STATE_IMAGE;
 
574
        /* Have to blit from cache */
 
575
        nr_blit_pixblock_pixblock (pb, dpb);
 
576
        nr_pixblock_release (dpb);
 
577
        pb->empty = FALSE;
 
578
        item->state |= NR_ARENA_ITEM_STATE_IMAGE;
663
579
    }
664
 
  }
665
 
        return item->state | NR_ARENA_ITEM_STATE_RENDER;
 
580
 
 
581
    return item->state | NR_ARENA_ITEM_STATE_RENDER;
666
582
}
667
583
 
668
584
unsigned int
669
585
nr_arena_item_invoke_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
670
586
{
671
 
        nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
672
 
        nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NR_ARENA_ITEM_STATE_INVALID);
673
 
        /* we originally short-circuited if the object state included
674
 
         * NR_ARENA_ITEM_STATE_CLIP (and showed a warning on the console);
675
 
         * anyone know why we stopped doing so?
676
 
         */
677
 
        nr_return_val_if_fail ((pb->area.x1 - pb->area.x0) >= (area->x1 - area->x0), NR_ARENA_ITEM_STATE_INVALID);
678
 
        nr_return_val_if_fail ((pb->area.y1 - pb->area.y0) >= (area->y1 - area->y0), NR_ARENA_ITEM_STATE_INVALID);
 
587
    nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
 
588
    nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
 
589
                           NR_ARENA_ITEM_STATE_INVALID);
 
590
    /* we originally short-circuited if the object state included
 
591
     * NR_ARENA_ITEM_STATE_CLIP (and showed a warning on the console);
 
592
     * anyone know why we stopped doing so?
 
593
     */
 
594
    nr_return_val_if_fail ((pb->area.x1 - pb->area.x0) >=
 
595
                           (area->x1 - area->x0),
 
596
                           NR_ARENA_ITEM_STATE_INVALID);
 
597
    nr_return_val_if_fail ((pb->area.y1 - pb->area.y0) >=
 
598
                           (area->y1 - area->y0),
 
599
                           NR_ARENA_ITEM_STATE_INVALID);
679
600
 
680
601
#ifdef NR_ARENA_ITEM_VERBOSE
681
 
        printf ("Invoke clip by %p: %d %d - %d %d, item bbox %d %d - %d %d\n", item, area->x0, area->y0, area->x1, area->y1, (&item->bbox)->x0, (&item->bbox)->y0, (&item->bbox)->x1, (&item->bbox)->y1);
 
602
    printf ("Invoke clip by %p: %d %d - %d %d, item bbox %d %d - %d %d\n",
 
603
            item, area->x0, area->y0, area->x1, area->y1, (&item->bbox)->x0,
 
604
            (&item->bbox)->y0, (&item->bbox)->x1, (&item->bbox)->y1);
682
605
#endif
683
606
 
684
 
        if (item->visible && nr_rect_l_test_intersect (area, &item->bbox)) {
685
 
                /* Need render that item */
686
 
                if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) {
687
 
                        return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS(item))->clip (item, area, pb);
688
 
                }
689
 
        }
 
607
    if (item->visible && nr_rect_l_test_intersect (area, &item->bbox)) {
 
608
        /* Need render that item */
 
609
        if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) {
 
610
            return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->
 
611
                clip (item, area, pb);
 
612
        }
 
613
    }
690
614
 
691
 
        return item->state;
 
615
    return item->state;
692
616
}
693
617
 
694
618
NRArenaItem *
695
 
nr_arena_item_invoke_pick (NRArenaItem *item, NR::Point p, double delta, unsigned int sticky)
 
619
nr_arena_item_invoke_pick (NRArenaItem *item, NR::Point p, double delta,
 
620
                           unsigned int sticky)
696
621
{
697
 
        nr_return_val_if_fail (item != NULL, NULL);
698
 
        nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
699
 
 
700
 
        // Sometimes there's no BBOX in item->state, reason unknown (bug 992817); I made this not an assert to remove the warning
701
 
        if (!(item->state & NR_ARENA_ITEM_STATE_BBOX) || !(item->state & NR_ARENA_ITEM_STATE_PICK))
702
 
                return NULL;
703
 
 
704
 
        if (!sticky && !(item->visible && item->sensitive)) return NULL;
705
 
        
706
 
        // TODO: rewrite using NR::Rect
707
 
        const double x = p[NR::X];
708
 
        const double y = p[NR::Y];
709
 
        
710
 
        if (((x + delta) >= item->bbox.x0) &&
711
 
            ((x - delta) <  item->bbox.x1) &&
712
 
            ((y + delta) >= item->bbox.y0) &&
713
 
            ((y - delta) <  item->bbox.y1)) {
714
 
                if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->pick)
715
 
                        return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->pick (item, p, delta, sticky);
716
 
        }
717
 
 
718
 
        return NULL;
 
622
    nr_return_val_if_fail (item != NULL, NULL);
 
623
    nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
 
624
 
 
625
    // Sometimes there's no BBOX in item->state, reason unknown (bug 992817); I made this not an assert to remove the warning
 
626
    if (!(item->state & NR_ARENA_ITEM_STATE_BBOX)
 
627
        || !(item->state & NR_ARENA_ITEM_STATE_PICK))
 
628
        return NULL;
 
629
 
 
630
    if (!sticky && !(item->visible && item->sensitive))
 
631
        return NULL;
 
632
 
 
633
    // TODO: rewrite using NR::Rect
 
634
    const double x = p[NR::X];
 
635
    const double y = p[NR::Y];
 
636
 
 
637
    if (((x + delta) >= item->bbox.x0) &&
 
638
        ((x - delta) < item->bbox.x1) &&
 
639
        ((y + delta) >= item->bbox.y0) && ((y - delta) < item->bbox.y1)) {
 
640
        if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->pick)
 
641
            return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->
 
642
                pick (item, p, delta, sticky);
 
643
    }
 
644
 
 
645
    return NULL;
719
646
}
720
647
 
721
648
void
722
 
nr_arena_item_request_update (NRArenaItem *item, unsigned int reset, unsigned int propagate)
 
649
nr_arena_item_request_update (NRArenaItem *item, unsigned int reset,
 
650
                              unsigned int propagate)
723
651
{
724
 
        nr_return_if_fail (item != NULL);
725
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
726
 
        nr_return_if_fail (!(reset & NR_ARENA_ITEM_STATE_INVALID));
727
 
 
728
 
        if (propagate && !item->propagate) item->propagate = TRUE;
729
 
 
730
 
        if (item->state & reset) {
731
 
                item->state &= ~reset;
732
 
                if (item->parent) {
733
 
                        nr_arena_item_request_update (item->parent, reset, FALSE);
734
 
                } else {
735
 
                        nr_arena_request_update (item->arena, item);
736
 
                }
737
 
        }
 
652
    nr_return_if_fail (item != NULL);
 
653
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
654
    nr_return_if_fail (!(reset & NR_ARENA_ITEM_STATE_INVALID));
 
655
 
 
656
    if (propagate && !item->propagate)
 
657
        item->propagate = TRUE;
 
658
 
 
659
    if (item->state & reset) {
 
660
        item->state &= ~reset;
 
661
        if (item->parent) {
 
662
            nr_arena_item_request_update (item->parent, reset, FALSE);
 
663
        } else {
 
664
            nr_arena_request_update (item->arena, item);
 
665
        }
 
666
    }
738
667
}
739
668
 
740
669
void
741
670
nr_arena_item_request_render (NRArenaItem *item)
742
671
{
743
 
        nr_return_if_fail (item != NULL);
744
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
672
    nr_return_if_fail (item != NULL);
 
673
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
745
674
 
746
 
        nr_arena_request_render_rect (item->arena, &item->bbox);
 
675
    nr_arena_request_render_rect (item->arena, &item->bbox);
747
676
}
748
677
 
749
678
/* Public */
751
680
NRArenaItem *
752
681
nr_arena_item_unparent (NRArenaItem *item)
753
682
{
754
 
        nr_return_val_if_fail (item != NULL, NULL);
755
 
        nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
756
 
 
757
 
        nr_arena_item_request_render (item);
758
 
 
759
 
        if (item->parent) {
760
 
                nr_arena_item_remove_child (item->parent, item);
761
 
        }
762
 
 
763
 
        return NULL;
 
683
    nr_return_val_if_fail (item != NULL, NULL);
 
684
    nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
 
685
 
 
686
    nr_arena_item_request_render (item);
 
687
 
 
688
    if (item->parent) {
 
689
        nr_arena_item_remove_child (item->parent, item);
 
690
    }
 
691
 
 
692
    return NULL;
764
693
}
765
694
 
766
695
void
767
696
nr_arena_item_append_child (NRArenaItem *parent, NRArenaItem *child)
768
697
{
769
 
        nr_return_if_fail (parent != NULL);
770
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (parent));
771
 
        nr_return_if_fail (child != NULL);
772
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (child));
773
 
        nr_return_if_fail (parent->arena == child->arena);
774
 
        nr_return_if_fail (child->parent == NULL);
775
 
        nr_return_if_fail (child->prev == NULL);
776
 
        nr_return_if_fail (child->next == NULL);
777
 
 
778
 
        nr_arena_item_add_child (parent, child, nr_arena_item_last_child (parent));
779
 
}
780
 
 
781
 
void
782
 
nr_arena_item_set_transform(NRArenaItem *item, NR::Matrix const &transform)
783
 
{
784
 
        NRMatrix const t(transform);
785
 
        nr_arena_item_set_transform(item, &t);
786
 
}
787
 
 
788
 
void
789
 
nr_arena_item_set_transform(NRArenaItem *item, NRMatrix const *transform)
790
 
{
791
 
        const NRMatrix *ms, *md;
792
 
 
793
 
        nr_return_if_fail (item != NULL);
794
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
795
 
 
796
 
        if (!transform && !item->transform) return;
797
 
 
798
 
        md = (item->transform) ? item->transform : &NR_MATRIX_IDENTITY;
799
 
        ms = (transform) ? transform : &NR_MATRIX_IDENTITY;
800
 
 
801
 
        if (!NR_MATRIX_DF_TEST_CLOSE (md, ms, NR_EPSILON)) {
802
 
                nr_arena_item_request_render (item);
803
 
                if (!transform || nr_matrix_test_identity (transform, NR_EPSILON)) {
804
 
                        /* Set to identity affine */
805
 
                        item->transform = NULL;
806
 
                } else {
807
 
                        if (!item->transform) item->transform = new (GC::ATOMIC) NRMatrix();
808
 
                        *item->transform = *transform;
809
 
                }
810
 
                nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
811
 
        }
 
698
    nr_return_if_fail (parent != NULL);
 
699
    nr_return_if_fail (NR_IS_ARENA_ITEM (parent));
 
700
    nr_return_if_fail (child != NULL);
 
701
    nr_return_if_fail (NR_IS_ARENA_ITEM (child));
 
702
    nr_return_if_fail (parent->arena == child->arena);
 
703
    nr_return_if_fail (child->parent == NULL);
 
704
    nr_return_if_fail (child->prev == NULL);
 
705
    nr_return_if_fail (child->next == NULL);
 
706
 
 
707
    nr_arena_item_add_child (parent, child, nr_arena_item_last_child (parent));
 
708
}
 
709
 
 
710
void
 
711
nr_arena_item_set_transform (NRArenaItem *item, NR::Matrix const &transform)
 
712
{
 
713
    NRMatrix const t (transform);
 
714
    nr_arena_item_set_transform (item, &t);
 
715
}
 
716
 
 
717
void
 
718
nr_arena_item_set_transform (NRArenaItem *item, NRMatrix const *transform)
 
719
{
 
720
    nr_return_if_fail (item != NULL);
 
721
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
722
 
 
723
    if (!transform && !item->transform)
 
724
        return;
 
725
 
 
726
    const NRMatrix *md = (item->transform) ? item->transform : &NR_MATRIX_IDENTITY;
 
727
    const NRMatrix *ms = (transform) ? transform : &NR_MATRIX_IDENTITY;
 
728
 
 
729
    if (!NR_MATRIX_DF_TEST_CLOSE (md, ms, NR_EPSILON)) {
 
730
        nr_arena_item_request_render (item);
 
731
        if (!transform || nr_matrix_test_identity (transform, NR_EPSILON)) {
 
732
            /* Set to identity affine */
 
733
            item->transform = NULL;
 
734
        } else {
 
735
            if (!item->transform)
 
736
                item->transform = new (GC::ATOMIC) NRMatrix ();
 
737
            *item->transform = *transform;
 
738
        }
 
739
        nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
 
740
    }
812
741
}
813
742
 
814
743
void
815
744
nr_arena_item_set_opacity (NRArenaItem *item, double opacity)
816
745
{
817
 
        nr_return_if_fail (item != NULL);
818
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
819
 
 
820
 
        nr_arena_item_request_render (item);
821
 
 
822
 
        item->opacity = (unsigned int) (opacity * 255.9999);
 
746
    nr_return_if_fail (item != NULL);
 
747
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
748
 
 
749
    nr_arena_item_request_render (item);
 
750
 
 
751
    item->opacity = (unsigned int) (opacity * 255.9999);
823
752
}
824
753
 
825
754
void
826
755
nr_arena_item_set_sensitive (NRArenaItem *item, unsigned int sensitive)
827
756
{
828
 
        nr_return_if_fail (item != NULL);
829
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
830
 
 
831
 
        /* fixme: mess with pick/repick... */
832
 
 
833
 
        item->sensitive = sensitive;
 
757
    nr_return_if_fail (item != NULL);
 
758
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
759
 
 
760
    /* fixme: mess with pick/repick... */
 
761
 
 
762
    item->sensitive = sensitive;
834
763
}
835
764
 
836
765
void
837
766
nr_arena_item_set_visible (NRArenaItem *item, unsigned int visible)
838
767
{
839
 
        nr_return_if_fail (item != NULL);
840
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
841
 
 
842
 
        item->visible = visible;
843
 
 
844
 
        nr_arena_item_request_render (item);
 
768
    nr_return_if_fail (item != NULL);
 
769
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
770
 
 
771
    item->visible = visible;
 
772
 
 
773
    nr_arena_item_request_render (item);
845
774
}
846
775
 
847
776
void
848
777
nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip)
849
778
{
850
 
        nr_return_if_fail (item != NULL);
851
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
852
 
        nr_return_if_fail (!clip || NR_IS_ARENA_ITEM (clip));
 
779
    nr_return_if_fail (item != NULL);
 
780
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
781
    nr_return_if_fail (!clip || NR_IS_ARENA_ITEM (clip));
853
782
 
854
 
        if (clip != item->clip) {
855
 
                nr_arena_item_request_render (item);
856
 
                if (item->clip) item->clip = nr_arena_item_detach (item, item->clip);
857
 
                if (clip) item->clip = nr_arena_item_attach (item, clip, NULL, NULL);
858
 
                nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
859
 
        }
 
783
    if (clip != item->clip) {
 
784
        nr_arena_item_request_render (item);
 
785
        if (item->clip)
 
786
            item->clip = nr_arena_item_detach (item, item->clip);
 
787
        if (clip)
 
788
            item->clip = nr_arena_item_attach (item, clip, NULL, NULL);
 
789
        nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
 
790
    }
860
791
}
861
792
 
862
793
void
863
794
nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask)
864
795
{
865
 
        nr_return_if_fail (item != NULL);
866
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
867
 
        nr_return_if_fail (!mask || NR_IS_ARENA_ITEM (mask));
 
796
    nr_return_if_fail (item != NULL);
 
797
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
798
    nr_return_if_fail (!mask || NR_IS_ARENA_ITEM (mask));
868
799
 
869
 
        if (mask != item->mask) {
870
 
                nr_arena_item_request_render (item);
871
 
                if (item->mask) item->mask = nr_arena_item_detach (item, item->mask);
872
 
                if (mask) item->mask = nr_arena_item_attach (item, mask, NULL, NULL);
873
 
                nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
874
 
        }
 
800
    if (mask != item->mask) {
 
801
        nr_arena_item_request_render (item);
 
802
        if (item->mask)
 
803
            item->mask = nr_arena_item_detach (item, item->mask);
 
804
        if (mask)
 
805
            item->mask = nr_arena_item_attach (item, mask, NULL, NULL);
 
806
        nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
 
807
    }
875
808
}
876
809
 
877
810
void
878
811
nr_arena_item_set_order (NRArenaItem *item, int order)
879
812
{
880
 
        NRArenaItem *children, *child, *ref;
881
 
        int pos;
882
 
 
883
 
        nr_return_if_fail (item != NULL);
884
 
        nr_return_if_fail (NR_IS_ARENA_ITEM (item));
885
 
 
886
 
        if (!item->parent) return;
887
 
 
888
 
        children = nr_arena_item_children (item->parent);
889
 
 
890
 
        ref = NULL;
891
 
        pos = 0;
892
 
        for (child = children; child != NULL; child = child->next) {
893
 
                if (pos >= order) break;
894
 
                if (child != item) {
895
 
                        ref = child;
896
 
                        pos += 1;
897
 
                }
898
 
        }
899
 
 
900
 
        nr_arena_item_set_child_position (item->parent, item, ref);
 
813
    nr_return_if_fail (item != NULL);
 
814
    nr_return_if_fail (NR_IS_ARENA_ITEM (item));
 
815
 
 
816
    if (!item->parent)
 
817
        return;
 
818
 
 
819
    NRArenaItem *children = nr_arena_item_children (item->parent);
 
820
 
 
821
    NRArenaItem *ref = NULL;
 
822
    int pos = 0;
 
823
    for (NRArenaItem *child = children; child != NULL; child = child->next) {
 
824
        if (pos >= order)
 
825
            break;
 
826
        if (child != item) {
 
827
            ref = child;
 
828
            pos += 1;
 
829
        }
 
830
    }
 
831
 
 
832
    nr_arena_item_set_child_position (item->parent, item, ref);
 
833
}
 
834
 
 
835
void
 
836
nr_arena_item_set_item_bbox (NRArenaItem *item, NR::Maybe<NR::Rect> &bbox)
 
837
{
 
838
    nr_return_if_fail(item != NULL);
 
839
    nr_return_if_fail(NR_IS_ARENA_ITEM(item));
 
840
 
 
841
    item->item_bbox = bbox;
 
842
}
 
843
 
 
844
/** Returns a background image for use with filter effects. */
 
845
NRPixBlock *
 
846
nr_arena_item_get_background (NRArenaItem const *item, int depth)
 
847
{
 
848
    NRPixBlock *pb;
 
849
    if (!item->background_pb)
 
850
        return NULL;
 
851
    if (item->background_new) {
 
852
        pb = new NRPixBlock ();
 
853
        nr_pixblock_setup_fast (pb, item->background_pb->mode,
 
854
                                item->background_pb->area.x0,
 
855
                                item->background_pb->area.y0,
 
856
                                item->background_pb->area.x1,
 
857
                                item->background_pb->area.y1, true);
 
858
        if (pb->size != NR_PIXBLOCK_SIZE_TINY && pb->data.px == NULL) // allocation failed
 
859
            return NULL;
 
860
    } else if (item->parent) {
 
861
        pb = nr_arena_item_get_background (item->parent, depth + 1);
 
862
    } else
 
863
        return NULL;
 
864
 
 
865
    if (depth > 0)
 
866
        nr_blit_pixblock_pixblock (pb, item->background_pb);
 
867
 
 
868
    return pb;
901
869
}
902
870
 
903
871
/* Helpers */
904
872
 
905
873
NRArenaItem *
906
 
nr_arena_item_attach (NRArenaItem *parent, NRArenaItem *child, NRArenaItem *prev, NRArenaItem *next)
 
874
nr_arena_item_attach (NRArenaItem *parent, NRArenaItem *child,
 
875
                      NRArenaItem *prev, NRArenaItem *next)
907
876
{
908
 
        nr_return_val_if_fail (parent != NULL, NULL);
909
 
        nr_return_val_if_fail (NR_IS_ARENA_ITEM (parent), NULL);
910
 
        nr_return_val_if_fail (child != NULL, NULL);
911
 
        nr_return_val_if_fail (NR_IS_ARENA_ITEM (child), NULL);
912
 
        nr_return_val_if_fail (child->parent == NULL, NULL);
913
 
        nr_return_val_if_fail (child->prev == NULL, NULL);
914
 
        nr_return_val_if_fail (child->next == NULL, NULL);
915
 
        nr_return_val_if_fail (!prev || NR_IS_ARENA_ITEM (prev), NULL);
916
 
        nr_return_val_if_fail (!prev || (prev->parent == parent), NULL);
917
 
        nr_return_val_if_fail (!prev || (prev->next == next), NULL);
918
 
        nr_return_val_if_fail (!next || NR_IS_ARENA_ITEM (next), NULL);
919
 
        nr_return_val_if_fail (!next || (next->parent == parent), NULL);
920
 
        nr_return_val_if_fail (!next || (next->prev == prev), NULL);
921
 
 
922
 
        child->parent = parent;
923
 
        child->prev = prev;
924
 
        child->next = next;
925
 
 
926
 
        if (prev) prev->next = child;
927
 
        if (next) next->prev = child;
928
 
 
929
 
        return child;
 
877
    nr_return_val_if_fail (parent != NULL, NULL);
 
878
    nr_return_val_if_fail (NR_IS_ARENA_ITEM (parent), NULL);
 
879
    nr_return_val_if_fail (child != NULL, NULL);
 
880
    nr_return_val_if_fail (NR_IS_ARENA_ITEM (child), NULL);
 
881
    nr_return_val_if_fail (child->parent == NULL, NULL);
 
882
    nr_return_val_if_fail (child->prev == NULL, NULL);
 
883
    nr_return_val_if_fail (child->next == NULL, NULL);
 
884
    nr_return_val_if_fail (!prev || NR_IS_ARENA_ITEM (prev), NULL);
 
885
    nr_return_val_if_fail (!prev || (prev->parent == parent), NULL);
 
886
    nr_return_val_if_fail (!prev || (prev->next == next), NULL);
 
887
    nr_return_val_if_fail (!next || NR_IS_ARENA_ITEM (next), NULL);
 
888
    nr_return_val_if_fail (!next || (next->parent == parent), NULL);
 
889
    nr_return_val_if_fail (!next || (next->prev == prev), NULL);
 
890
 
 
891
    child->parent = parent;
 
892
    child->prev = prev;
 
893
    child->next = next;
 
894
 
 
895
    if (prev)
 
896
        prev->next = child;
 
897
    if (next)
 
898
        next->prev = child;
 
899
 
 
900
    return child;
930
901
}
931
902
 
932
903
NRArenaItem *
933
904
nr_arena_item_detach (NRArenaItem *parent, NRArenaItem *child)
934
905
{
935
 
        NRArenaItem *prev, *next;
936
 
 
937
 
        nr_return_val_if_fail (parent != NULL, NULL);
938
 
        nr_return_val_if_fail (NR_IS_ARENA_ITEM (parent), NULL);
939
 
        nr_return_val_if_fail (child != NULL, NULL);
940
 
        nr_return_val_if_fail (NR_IS_ARENA_ITEM (child), NULL);
941
 
        nr_return_val_if_fail (child->parent == parent, NULL);
942
 
 
943
 
        prev = child->prev;
944
 
        next = child->next;
945
 
 
946
 
        child->parent = NULL;
947
 
        child->prev = NULL;
948
 
        child->next = NULL;
949
 
 
950
 
        if (prev) prev->next = next;
951
 
        if (next) next->prev = prev;
952
 
 
953
 
        return next;
 
906
    nr_return_val_if_fail (parent != NULL, NULL);
 
907
    nr_return_val_if_fail (NR_IS_ARENA_ITEM (parent), NULL);
 
908
    nr_return_val_if_fail (child != NULL, NULL);
 
909
    nr_return_val_if_fail (NR_IS_ARENA_ITEM (child), NULL);
 
910
    nr_return_val_if_fail (child->parent == parent, NULL);
 
911
 
 
912
    NRArenaItem *prev = child->prev;
 
913
    NRArenaItem *next = child->next;
 
914
 
 
915
    child->parent = NULL;
 
916
    child->prev = NULL;
 
917
    child->next = NULL;
 
918
 
 
919
    if (prev)
 
920
        prev->next = next;
 
921
    if (next)
 
922
        next->prev = prev;
 
923
 
 
924
    return next;
954
925
}
955
926
 
956
927
/*
957
 
 *
958
 
 * caches
959
 
 *
960
 
 */
961
 
 
962
 
#ifdef arena_item_tile_cache
963
 
typedef struct cache_entry {
964
 
  int             key;
965
 
  double          score;
966
 
  NRArenaItem*    owner;
967
 
  int             th,tv;
968
 
  int             prev,next;
969
 
  NRPixBlock      ipb;
970
 
  bool            hasMask;
971
 
  NRPixBlock      mpb;
972
 
} cache_entry;
973
 
 
974
 
int hash_max=2048,hash_fill=1024;
975
 
 
976
 
int            *keys=NULL;
977
 
int            nbCch=0;
978
 
 
979
 
int            nbEnt=0,maxEnt=0;
980
 
cache_entry*   entries=NULL;
981
 
 
982
 
//#define tile_cache_stats
983
 
#ifdef tile_cache_stats
984
 
double         hits=0,misses=0;
985
 
int            hitMissCount=0;
986
 
#endif
987
 
 
988
 
int hash_that(NRArenaItem* owner,int th,int tv)
989
 
{
990
 
  int res=GPOINTER_TO_INT(owner);
991
 
  res*=17;
992
 
  res+=th;
993
 
  res*=59;
994
 
  res+=tv;
995
 
  res*=217;
996
 
  if ( res < 0 ) res=-res;
997
 
  res%=hash_max;
998
 
  return res;
999
 
}
1000
 
 
1001
 
bool  test_cache(NRArenaItem* owner,int th,int tv,NRPixBlock &ipb,NRPixBlock &mpb,bool &hasMask)
1002
 
{
1003
 
  if ( keys == NULL ) {
1004
 
    hash_max = prefs_get_int_attribute ("options.arenatilescachesize", "value", 2048);
1005
 
    hash_fill=(hash_max*3)/4;
1006
 
    keys=(int*)malloc(hash_max*sizeof(int));
1007
 
    for (int i=0;i<hash_max;i++) keys[i]=-1;
1008
 
  }
1009
 
  int key=hash_that(owner,th,tv);
1010
 
  if ( keys[key] < 0 ) {
1011
 
#ifdef tile_cache_stats
1012
 
    misses+=1.0;
1013
 
#endif
1014
 
    return false;
1015
 
  }
1016
 
  int cur=keys[key];
1017
 
  while ( cur >= 0 && cur < nbEnt ) {
1018
 
    if ( entries[cur].owner == owner && entries[cur].th == th && entries[cur].tv == tv ) {
1019
 
      hasMask=entries[cur].hasMask;
1020
 
      ipb=entries[cur].ipb;
1021
 
      mpb=entries[cur].mpb;
1022
 
#ifdef tile_cache_stats
1023
 
      hits+=1.0;
1024
 
#endif
1025
 
      return true;
1026
 
    }
1027
 
    cur=entries[cur].next;
1028
 
  }
1029
 
#ifdef tile_cache_stats
1030
 
  misses+=1.0;
1031
 
#endif
1032
 
  return false;
1033
 
}
1034
 
void  remove_one_cache(int no)
1035
 
{
1036
 
  if ( no < 0 || no >= nbEnt ) return;
1037
 
 
1038
 
  nr_pixblock_release(&entries[no].ipb);
1039
 
  if ( entries[no].hasMask ) nr_pixblock_release(&entries[no].mpb);
1040
 
 
1041
 
  if ( entries[no].prev >= 0 ) entries[entries[no].prev].next=entries[no].next;
1042
 
  if ( entries[no].next >= 0 ) entries[entries[no].next].prev=entries[no].prev;
1043
 
  if ( entries[no].prev < 0 ) keys[entries[no].key]=entries[no].next;
1044
 
  entries[no].prev=entries[no].next=entries[no].key=-1;
1045
 
 
1046
 
  if ( no == nbEnt-1 ) {
1047
 
    nbEnt--;
1048
 
    return;
1049
 
  }
1050
 
  entries[no]=entries[--nbEnt];
1051
 
  if ( entries[no].prev >= 0 ) entries[entries[no].prev].next=no;
1052
 
  if ( entries[no].next >= 0 ) entries[entries[no].next].prev=no;
1053
 
  if ( entries[no].prev < 0 ) keys[entries[no].key]=no;
1054
 
}
1055
 
void  remove_caches(NRArenaItem* owner)
1056
 
{
1057
 
  if ( keys == NULL ) {
1058
 
    hash_max = prefs_get_int_attribute ("options.arenatilescachesize", "value", 2048);
1059
 
    hash_fill=(hash_max*3)/4;
1060
 
    keys=(int*)malloc(hash_max*sizeof(int));
1061
 
    for (int i=0;i<hash_max;i++) keys[i]=-1;
1062
 
  }
1063
 
  for (int i=nbEnt-1;i>=0;i--) {
1064
 
    if ( entries[i].owner == owner ) {
1065
 
      remove_one_cache(i);
1066
 
    }
1067
 
  }
1068
 
}
1069
 
void  age_cache(void)
1070
 
{
1071
 
  for (int i=0;i<nbEnt;i++) entries[i].score*=0.95;
1072
 
}
1073
 
bool  insert_cache(NRArenaItem* owner,int th,int tv,NRPixBlock *ipb,NRPixBlock *mpb,double activity,double duration)
1074
 
{
1075
 
  if ( keys == NULL ) {
1076
 
    hash_max = prefs_get_int_attribute ("options.arenatilescachesize", "value", 2048);
1077
 
    hash_fill=(hash_max*3)/4;
1078
 
    keys=(int*)malloc(hash_max*sizeof(int));
1079
 
    for (int i=0;i<hash_max;i++) keys[i]=-1;
1080
 
  }
1081
 
  for (int i=0;i<nbEnt;i++) entries[i].score*=0.95;
1082
 
#ifdef tile_cache_stats
1083
 
  hits*=0.95;
1084
 
  misses*=0.95;
1085
 
  hitMissCount++;
1086
 
  if ( hitMissCount > 100 ) {
1087
 
    hitMissCount=0;
1088
 
    printf("hit/miss = %f  used/total=%i/%i\n",(misses>0.001)?hits/misses:100000.0,nbEnt,hash_max); // localizing ok
1089
 
  }
1090
 
#endif
1091
 
  int    key=hash_that(owner,th,tv);
1092
 
  double nScore=/*activity**/duration;
1093
 
 
1094
 
  if ( keys[key] >= 0 ) {
1095
 
    int cur=keys[key];
1096
 
    while ( cur >= 0 && cur < nbEnt ) {
1097
 
      if ( entries[cur].owner == owner && entries[cur].th == th && entries[cur].tv == tv ) {
1098
 
        remove_one_cache(cur);
1099
 
        break;
1100
 
      }
1101
 
      cur=entries[cur].next;
1102
 
    }
1103
 
  }
1104
 
 
1105
 
  bool doAdd=false;
1106
 
  if ( nbEnt < hash_fill ) {
1107
 
    doAdd=true;
1108
 
  } else {
1109
 
    double    worstS=entries[0].score;
1110
 
    int       worstE=0;
1111
 
    for (int i=1;i<nbEnt;i++) {
1112
 
      if ( entries[i].score < worstS ) {
1113
 
        worstS=entries[i].score;
1114
 
        worstE=i;
1115
 
      }
1116
 
    }
1117
 
    if ( worstS < nScore ) {
1118
 
      doAdd=true;
1119
 
      remove_one_cache(worstE);
1120
 
    }
1121
 
  }
1122
 
  if ( doAdd == false ) return false;
1123
 
  if ( nbEnt >= maxEnt ) {
1124
 
    maxEnt=2*nbEnt+1;
1125
 
    entries=(cache_entry*)realloc(entries,maxEnt*sizeof(cache_entry));
1126
 
  }
1127
 
  entries[nbEnt].key=key;
1128
 
  entries[nbEnt].score=nScore;
1129
 
  entries[nbEnt].owner=owner;
1130
 
  entries[nbEnt].th=th;
1131
 
  entries[nbEnt].tv=tv;
1132
 
  entries[nbEnt].prev=entries[nbEnt].next=-1;
1133
 
  entries[nbEnt].ipb=*ipb;
1134
 
  if ( mpb ) {
1135
 
    entries[nbEnt].hasMask=true;
1136
 
    entries[nbEnt].mpb=*mpb;
1137
 
  } else {
1138
 
    entries[nbEnt].hasMask=false;
1139
 
  }
1140
 
  entries[nbEnt].next=keys[key];
1141
 
  if ( entries[nbEnt].next >= 0 ) entries[entries[nbEnt].next].prev=nbEnt;
1142
 
  keys[key]=nbEnt;
1143
 
 
1144
 
  nbEnt++;
1145
 
  return true;
1146
 
}
1147
 
#endif
1148
 
 
1149
 
 
1150
 
 
1151
 
 
 
928
  Local Variables:
 
929
  mode:c++
 
930
  c-file-style:"stroustrup"
 
931
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
932
  indent-tabs-mode:nil
 
933
  fill-column:99
 
934
  End:
 
935
*/
 
936
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :