1 #define __NR_ARENA_ITEM_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 #define noNR_ARENA_ITEM_VERBOSE
16 #define noNR_ARENA_ITEM_DEBUG_CASCADE
19 #include <libnr/nr-blit.h>
20 #include <libnr/nr-pixops.h>
21 #include "nr-arena.h"
22 #include "nr-arena-item.h"
23 #include "gc-core.h"
25 #include "nr-filter.h"
26 #include "libnr/nr-rect.h"
27 #include "nr-arena-group.h"
29 namespace GC = Inkscape::GC;
31 static void nr_arena_item_class_init (NRArenaItemClass *klass);
32 static void nr_arena_item_init (NRArenaItem *item);
33 static void nr_arena_item_private_finalize (NRObject *object);
35 #ifdef arena_item_tile_cache
36 bool insert_cache (NRArenaItem *owner, int th, int tv, NRPixBlock *ipb,
37 NRPixBlock *mpb, double activity, double duration);
38 void remove_caches (NRArenaItem *owner);
39 bool test_cache (NRArenaItem *owner, int th, int tv, NRPixBlock & ipb,
40 NRPixBlock &mpb, bool &hasMask);
41 #endif
43 static NRObjectClass *parent_class;
45 NRType
46 nr_arena_item_get_type (void)
47 {
48 static NRType type = 0;
49 if (!type) {
50 type = nr_object_register_type (NR_TYPE_OBJECT,
51 "NRArenaItem",
52 sizeof (NRArenaItemClass),
53 sizeof (NRArenaItem),
54 (void (*)(NRObjectClass *))
55 nr_arena_item_class_init,
56 (void (*)(NRObject *))
57 nr_arena_item_init);
58 }
59 return type;
60 }
62 static void
63 nr_arena_item_class_init (NRArenaItemClass *klass)
64 {
65 NRObjectClass *object_class;
67 object_class = (NRObjectClass *) klass;
69 parent_class = ((NRObjectClass *) klass)->parent;
71 object_class->finalize = nr_arena_item_private_finalize;
72 object_class->cpp_ctor = NRObject::invoke_ctor < NRArenaItem >;
73 }
75 static void
76 nr_arena_item_init (NRArenaItem *item)
77 {
78 item->arena = NULL;
79 item->parent = NULL;
80 item->next = item->prev = NULL;
82 item->key = 0;
84 item->state = 0;
85 item->sensitive = TRUE;
86 item->visible = TRUE;
88 memset (&item->bbox, 0, sizeof (item->bbox));
89 item->transform = NULL;
90 item->opacity = 255;
91 item->render_opacity = FALSE;
93 #ifdef arena_item_tile_cache
94 item->activity = 0.0;
95 item->skipCaching = false;
96 #endif
98 item->transform = NULL;
99 item->clip = NULL;
100 item->mask = NULL;
101 item->px = NULL;
102 item->data = NULL;
103 item->filter = NULL;
104 item->background_pb = NULL;
105 item->background_new = false;
106 }
108 static void
109 nr_arena_item_private_finalize (NRObject *object)
110 {
111 NRArenaItem *item = static_cast < NRArenaItem * >(object);
113 #ifdef arena_item_tile_cache
114 remove_caches (item);
115 #endif
117 item->px = NULL;
118 item->transform = NULL;
120 ((NRObjectClass *) (parent_class))->finalize (object);
121 }
123 NRArenaItem *
124 nr_arena_item_children (NRArenaItem *item)
125 {
126 nr_return_val_if_fail (item != NULL, NULL);
127 nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
129 if (NR_ARENA_ITEM_VIRTUAL (item, children))
130 return NR_ARENA_ITEM_VIRTUAL (item, children) (item);
132 return NULL;
133 }
135 NRArenaItem *
136 nr_arena_item_last_child (NRArenaItem *item)
137 {
138 nr_return_val_if_fail (item != NULL, NULL);
139 nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
141 if (NR_ARENA_ITEM_VIRTUAL (item, last_child)) {
142 return NR_ARENA_ITEM_VIRTUAL (item, last_child) (item);
143 } else {
144 NRArenaItem *ref = nr_arena_item_children (item);
145 if (ref)
146 while (ref->next)
147 ref = ref->next;
148 return ref;
149 }
150 }
152 void
153 nr_arena_item_add_child (NRArenaItem *item, NRArenaItem *child,
154 NRArenaItem *ref)
155 {
156 nr_return_if_fail (item != NULL);
157 nr_return_if_fail (NR_IS_ARENA_ITEM (item));
158 nr_return_if_fail (child != NULL);
159 nr_return_if_fail (NR_IS_ARENA_ITEM (child));
160 nr_return_if_fail (child->parent == NULL);
161 nr_return_if_fail (child->prev == NULL);
162 nr_return_if_fail (child->next == NULL);
163 nr_return_if_fail (child->arena == item->arena);
164 nr_return_if_fail (child != ref);
165 nr_return_if_fail (!ref || NR_IS_ARENA_ITEM (ref));
166 nr_return_if_fail (!ref || (ref->parent == item));
168 if (NR_ARENA_ITEM_VIRTUAL (item, add_child))
169 NR_ARENA_ITEM_VIRTUAL (item, add_child) (item, child, ref);
170 }
172 void
173 nr_arena_item_remove_child (NRArenaItem *item, NRArenaItem *child)
174 {
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);
181 if (NR_ARENA_ITEM_VIRTUAL (item, remove_child))
182 NR_ARENA_ITEM_VIRTUAL (item, remove_child) (item, child);
183 }
185 void
186 nr_arena_item_set_child_position (NRArenaItem *item, NRArenaItem *child,
187 NRArenaItem *ref)
188 {
189 nr_return_if_fail (item != NULL);
190 nr_return_if_fail (NR_IS_ARENA_ITEM (item));
191 nr_return_if_fail (child != NULL);
192 nr_return_if_fail (NR_IS_ARENA_ITEM (child));
193 nr_return_if_fail (child->parent == item);
194 nr_return_if_fail (!ref || NR_IS_ARENA_ITEM (ref));
195 nr_return_if_fail (!ref || (ref->parent == item));
197 if (NR_ARENA_ITEM_VIRTUAL (item, set_child_position))
198 NR_ARENA_ITEM_VIRTUAL (item, set_child_position) (item, child, ref);
199 }
201 NRArenaItem *
202 nr_arena_item_ref (NRArenaItem *item)
203 {
204 nr_object_ref ((NRObject *) item);
206 return item;
207 }
209 NRArenaItem *
210 nr_arena_item_unref (NRArenaItem *item)
211 {
212 nr_object_unref ((NRObject *) item);
214 return NULL;
215 }
217 unsigned int
218 nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
219 unsigned int state, unsigned int reset)
220 {
221 NRGC childgc (gc);
223 nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
224 nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
225 NR_ARENA_ITEM_STATE_INVALID);
226 nr_return_val_if_fail (!(state & NR_ARENA_ITEM_STATE_INVALID),
227 NR_ARENA_ITEM_STATE_INVALID);
229 #ifdef NR_ARENA_ITEM_DEBUG_CASCADE
230 printf ("Update %s:%p %x %x %x\n",
231 nr_type_name_from_instance ((GTypeInstance *) item), item, state,
232 item->state, reset);
233 #endif
235 /* return if in error */
236 if (item->state & NR_ARENA_ITEM_STATE_INVALID)
237 return item->state;
238 /* Set reset flags according to propagation status */
239 if (item->propagate) {
240 reset |= ~item->state;
241 item->propagate = FALSE;
242 }
243 /* Reset our state */
244 item->state &= ~reset;
245 /* Return if NOP */
246 if (!(~item->state & state))
247 return item->state;
248 /* Test whether to return immediately */
249 if (area && (item->state & NR_ARENA_ITEM_STATE_BBOX)) {
250 if (!nr_rect_l_test_intersect (area, &item->bbox))
251 return item->state;
252 }
254 /* Reset image cache, if not to be kept */
255 if (!(item->state & NR_ARENA_ITEM_STATE_IMAGE) && (item->px)) {
256 item->px = NULL;
257 }
258 #ifdef arena_item_tile_cache
259 remove_caches (item);
260 #endif
262 /* Set up local gc */
263 childgc = *gc;
264 if (item->transform) {
265 nr_matrix_multiply (&childgc.transform, item->transform,
266 &childgc.transform);
267 }
268 /* Remember the transformation matrix */
269 item->ctm = childgc.transform;
271 /* Invoke the real method */
272 item->state =
273 NR_ARENA_ITEM_VIRTUAL (item, update) (item, area, &childgc, state,
274 reset);
275 if (item->state & NR_ARENA_ITEM_STATE_INVALID)
276 return item->state;
277 /* Enlarge the bounding box to contain filter effects */
278 if (item->filter) {
279 item->filter->bbox_enlarge (item->bbox);
280 }
282 /* Clipping */
283 if (item->clip) {
284 unsigned int newstate = nr_arena_item_invoke_update (item->clip, area, &childgc, state, reset);
285 if (newstate & NR_ARENA_ITEM_STATE_INVALID) {
286 item->state |= NR_ARENA_ITEM_STATE_INVALID;
287 return item->state;
288 }
289 nr_rect_l_intersect (&item->bbox, &item->bbox, &item->clip->bbox);
290 }
291 /* Masking */
292 if (item->mask) {
293 unsigned int newstate = nr_arena_item_invoke_update (item->mask, area, &childgc, state, reset);
294 if (newstate & NR_ARENA_ITEM_STATE_INVALID) {
295 item->state |= NR_ARENA_ITEM_STATE_INVALID;
296 return item->state;
297 }
298 nr_rect_l_intersect (&item->bbox, &item->bbox, &item->mask->bbox);
299 }
301 return item->state;
302 }
304 /**
305 * Render item to pixblock.
306 *
307 * \return Has NR_ARENA_ITEM_STATE_RENDER set on success.
308 */
310 unsigned int
311 nr_arena_item_invoke_render (NRArenaItem *item, NRRectL const *area,
312 NRPixBlock *pb, unsigned int flags)
313 {
314 bool outline = (item->arena->rendermode == RENDERMODE_OUTLINE);
316 nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
317 nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
318 NR_ARENA_ITEM_STATE_INVALID);
319 nr_return_val_if_fail (item->state & NR_ARENA_ITEM_STATE_BBOX,
320 item->state);
322 #ifdef NR_ARENA_ITEM_VERBOSE
323 printf ("Invoke render %p: %d %d - %d %d\n", item, area->x0, area->y0,
324 area->x1, area->y1);
325 #endif
327 #ifdef arena_item_tile_cache
328 item->activity *= 0.5;
329 #endif
331 /* If we are outside bbox just return successfully */
332 if (!item->visible)
333 return item->state | NR_ARENA_ITEM_STATE_RENDER;
335 NRRectL carea;
336 nr_rect_l_intersect (&carea, area, &item->bbox);
337 if (nr_rect_l_test_empty (&carea))
338 return item->state | NR_ARENA_ITEM_STATE_RENDER;
339 if (item->filter && !outline) {
340 nr_rect_l_enlarge (&carea, item->filter->get_enlarge (item->ctm));
341 nr_rect_l_intersect (&carea, &carea, &item->bbox);
342 }
344 NRPixBlock cpb;
345 if (item->px) {
346 /* Has cache pixblock, render this and return */
347 nr_pixblock_setup_extern (&cpb, NR_PIXBLOCK_MODE_R8G8B8A8P,
348 /* fixme: This probably cannot overflow, because we render only if visible */
349 /* fixme: and pixel cache is there only for small items */
350 /* fixme: But this still needs extra check (Lauris) */
351 item->bbox.x0, item->bbox.y0,
352 item->bbox.x1, item->bbox.y1,
353 item->px,
354 4 * (item->bbox.x1 - item->bbox.x0), FALSE,
355 FALSE);
356 nr_blit_pixblock_pixblock (pb, &cpb);
357 nr_pixblock_release (&cpb);
358 pb->empty = FALSE;
359 return item->state | NR_ARENA_ITEM_STATE_RENDER;
360 }
362 NRPixBlock *dpb = pb;
363 bool canCache = false;
364 #ifdef arena_item_tile_cache
365 bool checkCache = false;
366 int tile_h = 0, tile_v = 0;
367 #endif
368 /* Setup cache if we can */
369 if ((!(flags & NR_ARENA_ITEM_RENDER_NO_CACHE)) &&
370 (carea.x0 <= item->bbox.x0) && (carea.y0 <= item->bbox.y0) &&
371 (carea.x1 >= item->bbox.x1) && (carea.y1 >= item->bbox.y1) &&
372 (((item->bbox.x1 - item->bbox.x0) * (item->bbox.y1 -
373 item->bbox.y0)) <= 4096)) {
374 // Item bbox is fully in renderable area and size is acceptable
375 carea.x0 = item->bbox.x0;
376 carea.y0 = item->bbox.y0;
377 carea.x1 = item->bbox.x1;
378 carea.y1 = item->bbox.y1;
379 item->px =
380 new (GC::ATOMIC) unsigned char[4 * (carea.x1 - carea.x0) *
381 (carea.y1 - carea.y0)];
382 nr_pixblock_setup_extern (&cpb, NR_PIXBLOCK_MODE_R8G8B8A8P, carea.x0,
383 carea.y0, carea.x1, carea.y1, item->px,
384 4 * (carea.x1 - carea.x0), TRUE, TRUE);
385 cpb.visible_area = pb->visible_area;
386 dpb = &cpb;
387 // Set nocache flag for downstream rendering
388 flags |= NR_ARENA_ITEM_RENDER_NO_CACHE;
389 } else {
390 #ifdef arena_item_tile_cache
391 if (item->skipCaching) {
392 } else {
393 int
394 tl = area->x0 & (~127);
395 int
396 tt = area->y0 & (~127);
397 if (area->x1 <= tl + 128 && area->y1 <= tt + 128) {
398 checkCache = true;
399 tile_h = tl / 128;
400 tile_v = tt / 128;
401 int
402 surf = (area->x1 - area->x0) * (area->y1 - area->y0);
403 if (surf >= 4096) {
404 canCache = true;
405 carea.x0 = tl;
406 carea.y0 = tt;
407 carea.x1 = tl + 128;
408 carea.y1 = tt + 128;
409 }
410 }
411 }
412 #endif
413 }
415 #ifdef arena_item_tile_cache
416 item->activity += 1.0;
417 #endif
419 #ifdef arena_item_tile_cache
420 if (checkCache) {
421 NRPixBlock
422 ipb,
423 mpb;
424 bool
425 hasMask;
426 if (test_cache (item, tile_h, tile_v, ipb, mpb, hasMask)) {
427 // youpi! c'etait deja cache
428 if (hasMask) {
429 nr_blit_pixblock_pixblock_mask (dpb, &ipb, &mpb);
430 } else if (((item->opacity != 255) && !item->render_opacity)) {
431 nr_blit_pixblock_pixblock_alpha (dpb, &ipb, item->opacity);
432 } else {
433 nr_blit_pixblock_pixblock (pb, &ipb);
434 }
435 pb->empty = FALSE;
436 return item->state | NR_ARENA_ITEM_STATE_RENDER;
437 }
438 }
439 #endif
440 if (canCache) {
441 #ifdef arena_item_tile_cache
442 // nota: exclusif de dpb != pb, donc pas de cas particulier a la fin
444 // struct timeval start_time,end_time;
445 // gettimeofday(&start_time,NULL);
446 GTimeVal start_time, end_time;
447 g_get_current_time (&start_time);
448 int duration = 0;
450 /* Setup and render item buffer */
451 NRPixBlock ipb;
452 nr_pixblock_setup_fast (&ipb, NR_PIXBLOCK_MODE_R8G8B8A8P, carea.x0,
453 carea.y0, carea.x1, carea.y1, TRUE);
455 // if memory allocation failed, abort render
456 if (ipb.data.px == NULL) {
457 nr_pixblock_release (&ipb);
458 return (item->state);
459 }
461 ipb.visible_area = pb->visible_area;
462 {
463 unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (item, &carea, &ipb, flags);
464 if (state & NR_ARENA_ITEM_STATE_INVALID) {
465 /* Clean up and return error */
466 nr_pixblock_release (&ipb);
467 if (dpb != pb)
468 nr_pixblock_release (dpb);
469 item->state |= NR_ARENA_ITEM_STATE_INVALID;
470 return item->state;
471 }
472 }
473 ipb.empty = FALSE;
475 if (item->clip || item->mask) {
476 /* Setup mask pixblock */
477 NRPixBlock mpb;
478 nr_pixblock_setup_fast (&mpb, NR_PIXBLOCK_MODE_A8, carea.x0, carea.y0, carea.x1, carea.y1, TRUE);
480 if (mpb.data.px != NULL) { // if memory allocation was successful
482 mpb.visible_area = pb->visible_area;
483 /* Do clip if needed */
484 if (item->clip) {
485 unsigned int state = nr_arena_item_invoke_clip (item->clip, &carea, &mpb);
486 if (state & NR_ARENA_ITEM_STATE_INVALID) {
487 /* Clean up and return error */
488 nr_pixblock_release (&mpb);
489 nr_pixblock_release (&ipb);
490 if (dpb != pb)
491 nr_pixblock_release (dpb);
492 item->state |= NR_ARENA_ITEM_STATE_INVALID;
493 return item->state;
494 }
495 mpb.empty = FALSE;
496 }
497 /* Do mask if needed */
498 if (item->mask) {
499 NRPixBlock tpb;
500 /* Set up yet another temporary pixblock */
501 nr_pixblock_setup_fast (&tpb, NR_PIXBLOCK_MODE_R8G8B8A8N,
502 carea.x0, carea.y0, carea.x1,
503 carea.y1, TRUE);
505 if (tpb.data.px != NULL) { // if memory allocation was successful
507 tpb.visible_area = pb->visible_area;
508 unsigned int state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (item->mask, &carea, &tpb, flags);
509 if (state & NR_ARENA_ITEM_STATE_INVALID) {
510 /* Clean up and return error */
511 nr_pixblock_release (&tpb);
512 nr_pixblock_release (&mpb);
513 nr_pixblock_release (&ipb);
514 if (dpb != pb)
515 nr_pixblock_release (dpb);
516 item->state |= NR_ARENA_ITEM_STATE_INVALID;
517 return item->state;
518 }
519 /* Composite with clip */
520 if (item->clip) {
521 int x, y;
522 for (y = carea.y0; y < carea.y1; y++) {
523 unsigned char *s, *d;
524 s = NR_PIXBLOCK_PX (&tpb) + (y - carea.y0) * tpb.rs;
525 d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs;
526 for (x = carea.x0; x < carea.x1; x++) {
527 unsigned int m;
528 m = ((s[0] + s[1] + s[2]) * s[3] +
529 127) / (3 * 255);
530 d[0] = NR_PREMUL (d[0], m);
531 s += 4;
532 d += 1;
533 }
534 }
535 } else {
536 int x, y;
537 for (y = carea.y0; y < carea.y1; y++) {
538 unsigned char *s, *d;
539 s = NR_PIXBLOCK_PX (&tpb) + (y - carea.y0) * tpb.rs;
540 d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs;
541 for (x = carea.x0; x < carea.x1; x++) {
542 unsigned int m;
543 m = ((s[0] + s[1] + s[2]) * s[3] +
544 127) / (3 * 255);
545 d[0] = m;
546 s += 4;
547 d += 1;
548 }
549 }
550 mpb.empty = FALSE;
551 }
552 }
553 nr_pixblock_release (&tpb);
554 }
555 /* Multiply with opacity if needed */
556 if ((item->opacity != 255) && !item->render_opacity && !outline) {
557 int x, y;
558 unsigned int a;
559 a = item->opacity;
560 for (y = carea.y0; y < carea.y1; y++) {
561 unsigned char *d;
562 d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs;
563 for (x = carea.x0; x < carea.x1; x++) {
564 d[0] = NR_PREMUL (d[0], a);
565 d += 1;
566 }
567 }
568 }
569 /* Compose rendering pixblock int destination */
570 // gettimeofday(&end_time,NULL);
571 g_get_current_time (&end_time);
572 duration =
573 (end_time.tv_sec - start_time.tv_sec) * 1000 +
574 (end_time.tv_usec - start_time.tv_usec) / 1000;
575 if (!(ipb.empty)) {
576 nr_blit_pixblock_pixblock_mask (dpb, &ipb, &mpb);
577 if (insert_cache
578 (item, tile_h, tile_v, &ipb, &mpb, item->activity,
579 (double) duration)) {
580 } else {
581 nr_pixblock_release (&mpb);
582 nr_pixblock_release (&ipb);
583 }
584 dpb->empty = FALSE;
585 } else {
586 nr_pixblock_release (&ipb);
587 }
588 }
589 } else
590 if (((item->opacity != 255) && !item->render_opacity
591 && !outline)) {
592 /* Opacity only */
593 // gettimeofday(&end_time,NULL);
594 g_get_current_time (&end_time);
595 duration =
596 (end_time.tv_sec - start_time.tv_sec) * 1000 +
597 (end_time.tv_usec - start_time.tv_usec) / 1000;
598 if (!(ipb.empty)) {
599 nr_blit_pixblock_pixblock_alpha (dpb, &ipb, item->opacity);
600 if (insert_cache
601 (item, tile_h, tile_v, &ipb, NULL, item->activity,
602 (double) duration)) {
603 } else {
604 nr_pixblock_release (&ipb);
605 }
606 dpb->empty = FALSE;
607 } else {
608 nr_pixblock_release (&ipb);
609 }
610 } else {
611 // gettimeofday(&end_time,NULL);
612 g_get_current_time (&end_time);
613 duration =
614 (end_time.tv_sec - start_time.tv_sec) * 1000 +
615 (end_time.tv_usec - start_time.tv_usec) / 1000;
616 if (!(ipb.empty)) {
617 nr_blit_pixblock_pixblock (dpb, &ipb);
618 if (insert_cache
619 (item, tile_h, tile_v, &ipb, NULL, item->activity,
620 (double) duration)) {
621 } else {
622 nr_pixblock_release (&ipb);
623 }
624 dpb->empty = FALSE;
625 } else {
626 nr_pixblock_release (&ipb);
627 }
628 }
629 #endif
630 } else {
631 /* Determine, whether we need temporary buffer */
632 if (item->clip || item->mask
633 || ((item->opacity != 255) && !item->render_opacity && !outline)
634 || (item->filter && !outline) || item->background_new
635 || (item->parent && item->parent->background_pb)) {
637 /* Setup and render item buffer */
638 NRPixBlock ipb;
639 nr_pixblock_setup_fast (&ipb, NR_PIXBLOCK_MODE_R8G8B8A8P,
640 carea.x0, carea.y0, carea.x1, carea.y1,
641 TRUE);
643 // if memory allocation failed, abort render
644 if (ipb.data.px == NULL) {
645 nr_pixblock_release (&ipb);
646 return (item->state);
647 }
649 /* If background access is used, save the pixblock address.
650 * This address is set to NULL at the end of this block */
651 if (item->background_new
652 || (item->parent && item->parent->background_pb)) {
653 item->background_pb = &ipb;
654 }
655 ipb.visible_area = pb->visible_area;
656 unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (item, &carea, &ipb, flags);
657 if (state & NR_ARENA_ITEM_STATE_INVALID) {
658 /* Clean up and return error */
659 nr_pixblock_release (&ipb);
660 if (dpb != pb)
661 nr_pixblock_release (dpb);
662 item->state |= NR_ARENA_ITEM_STATE_INVALID;
663 return item->state;
664 }
665 ipb.empty = FALSE;
667 /* Run filtering, if a filter is set for this object */
668 if (item->filter && !outline) {
669 item->filter->render (item, &ipb);
670 }
672 if (item->clip || item->mask) {
673 /* Setup mask pixblock */
674 NRPixBlock mpb;
675 nr_pixblock_setup_fast (&mpb, NR_PIXBLOCK_MODE_A8, carea.x0,
676 carea.y0, carea.x1, carea.y1, TRUE);
678 if (mpb.data.px != NULL) { // if memory allocation was successful
680 mpb.visible_area = pb->visible_area;
681 /* Do clip if needed */
682 if (item->clip) {
683 state = nr_arena_item_invoke_clip (item->clip, &carea, &mpb);
684 if (state & NR_ARENA_ITEM_STATE_INVALID) {
685 /* Clean up and return error */
686 nr_pixblock_release (&mpb);
687 nr_pixblock_release (&ipb);
688 if (dpb != pb)
689 nr_pixblock_release (dpb);
690 item->state |= NR_ARENA_ITEM_STATE_INVALID;
691 return item->state;
692 }
693 mpb.empty = FALSE;
694 }
695 /* Do mask if needed */
696 if (item->mask) {
697 NRPixBlock tpb;
698 /* Set up yet another temporary pixblock */
699 nr_pixblock_setup_fast (&tpb, NR_PIXBLOCK_MODE_R8G8B8A8N,
700 carea.x0, carea.y0, carea.x1,
701 carea.y1, TRUE);
703 if (tpb.data.px != NULL) { // if memory allocation was successful
705 tpb.visible_area = pb->visible_area;
706 unsigned int state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (item->mask, &carea, &tpb, flags);
707 if (state & NR_ARENA_ITEM_STATE_INVALID) {
708 /* Clean up and return error */
709 nr_pixblock_release (&tpb);
710 nr_pixblock_release (&mpb);
711 nr_pixblock_release (&ipb);
712 if (dpb != pb)
713 nr_pixblock_release (dpb);
714 item->state |= NR_ARENA_ITEM_STATE_INVALID;
715 return item->state;
716 }
717 /* Composite with clip */
718 if (item->clip) {
719 int x, y;
720 for (y = carea.y0; y < carea.y1; y++) {
721 unsigned char *s, *d;
722 s = NR_PIXBLOCK_PX (&tpb) + (y -
723 carea.y0) * tpb.rs;
724 d = NR_PIXBLOCK_PX (&mpb) + (y -
725 carea.y0) * mpb.rs;
726 for (x = carea.x0; x < carea.x1; x++) {
727 unsigned int m;
728 m = NR_PREMUL_112 (s[0] + s[1] + s[2], s[3]);
729 d[0] =
730 FAST_DIV_ROUND < 3 * 255 * 255 >
731 (NR_PREMUL_123 (d[0], m));
732 s += 4;
733 d += 1;
734 }
735 }
736 } else {
737 int x, y;
738 for (y = carea.y0; y < carea.y1; y++) {
739 unsigned char *s, *d;
740 s = NR_PIXBLOCK_PX (&tpb) + (y -
741 carea.y0) * tpb.rs;
742 d = NR_PIXBLOCK_PX (&mpb) + (y -
743 carea.y0) * mpb.rs;
744 for (x = carea.x0; x < carea.x1; x++) {
745 unsigned int m;
746 m = NR_PREMUL_112 (s[0] + s[1] + s[2], s[3]);
747 d[0] = FAST_DIV_ROUND < 3 * 255 > (m);
748 s += 4;
749 d += 1;
750 }
751 }
752 mpb.empty = FALSE;
753 }
754 }
755 nr_pixblock_release (&tpb);
756 }
757 /* Multiply with opacity if needed */
758 if ((item->opacity != 255) && !item->render_opacity
759 && !outline) {
760 int x, y;
761 unsigned int a;
762 a = item->opacity;
763 for (y = carea.y0; y < carea.y1; y++) {
764 unsigned char *d;
765 d = NR_PIXBLOCK_PX (&mpb) + (y - carea.y0) * mpb.rs;
766 for (x = carea.x0; x < carea.x1; x++) {
767 d[0] = NR_PREMUL_111 (d[0], a);
768 d += 1;
769 }
770 }
771 }
772 /* Compose rendering pixblock int destination */
773 nr_blit_pixblock_pixblock_mask (dpb, &ipb, &mpb);
774 }
775 nr_pixblock_release (&mpb);
776 /* This pointer wouldn't be valid outside this block, so clear it */
777 item->background_pb = NULL;
778 } else {
779 /* Opacity only */
780 nr_blit_pixblock_pixblock_alpha (dpb, &ipb, item->opacity);
781 }
782 nr_pixblock_release (&ipb);
783 dpb->empty = FALSE;
784 } else {
785 /* Just render */
786 unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (item, &carea, dpb, flags);
787 if (state & NR_ARENA_ITEM_STATE_INVALID) {
788 /* Clean up and return error */
789 if (dpb != pb)
790 nr_pixblock_release (dpb);
791 item->state |= NR_ARENA_ITEM_STATE_INVALID;
792 return item->state;
793 }
794 dpb->empty = FALSE;
795 }
797 if (dpb != pb) {
798 /* Have to blit from cache */
799 nr_blit_pixblock_pixblock (pb, dpb);
800 nr_pixblock_release (dpb);
801 pb->empty = FALSE;
802 item->state |= NR_ARENA_ITEM_STATE_IMAGE;
803 }
804 }
805 return item->state | NR_ARENA_ITEM_STATE_RENDER;
806 }
808 unsigned int
809 nr_arena_item_invoke_clip (NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
810 {
811 nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
812 nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
813 NR_ARENA_ITEM_STATE_INVALID);
814 /* we originally short-circuited if the object state included
815 * NR_ARENA_ITEM_STATE_CLIP (and showed a warning on the console);
816 * anyone know why we stopped doing so?
817 */
818 nr_return_val_if_fail ((pb->area.x1 - pb->area.x0) >=
819 (area->x1 - area->x0),
820 NR_ARENA_ITEM_STATE_INVALID);
821 nr_return_val_if_fail ((pb->area.y1 - pb->area.y0) >=
822 (area->y1 - area->y0),
823 NR_ARENA_ITEM_STATE_INVALID);
825 #ifdef NR_ARENA_ITEM_VERBOSE
826 printf ("Invoke clip by %p: %d %d - %d %d, item bbox %d %d - %d %d\n",
827 item, area->x0, area->y0, area->x1, area->y1, (&item->bbox)->x0,
828 (&item->bbox)->y0, (&item->bbox)->x1, (&item->bbox)->y1);
829 #endif
831 if (item->visible && nr_rect_l_test_intersect (area, &item->bbox)) {
832 /* Need render that item */
833 if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) {
834 return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->
835 clip (item, area, pb);
836 }
837 }
839 return item->state;
840 }
842 NRArenaItem *
843 nr_arena_item_invoke_pick (NRArenaItem *item, NR::Point p, double delta,
844 unsigned int sticky)
845 {
846 nr_return_val_if_fail (item != NULL, NULL);
847 nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
849 // Sometimes there's no BBOX in item->state, reason unknown (bug 992817); I made this not an assert to remove the warning
850 if (!(item->state & NR_ARENA_ITEM_STATE_BBOX)
851 || !(item->state & NR_ARENA_ITEM_STATE_PICK))
852 return NULL;
854 if (!sticky && !(item->visible && item->sensitive))
855 return NULL;
857 // TODO: rewrite using NR::Rect
858 const double x = p[NR::X];
859 const double y = p[NR::Y];
861 if (((x + delta) >= item->bbox.x0) &&
862 ((x - delta) < item->bbox.x1) &&
863 ((y + delta) >= item->bbox.y0) && ((y - delta) < item->bbox.y1)) {
864 if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->pick)
865 return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->
866 pick (item, p, delta, sticky);
867 }
869 return NULL;
870 }
872 void
873 nr_arena_item_request_update (NRArenaItem *item, unsigned int reset,
874 unsigned int propagate)
875 {
876 nr_return_if_fail (item != NULL);
877 nr_return_if_fail (NR_IS_ARENA_ITEM (item));
878 nr_return_if_fail (!(reset & NR_ARENA_ITEM_STATE_INVALID));
880 if (propagate && !item->propagate)
881 item->propagate = TRUE;
883 if (item->state & reset) {
884 item->state &= ~reset;
885 if (item->parent) {
886 nr_arena_item_request_update (item->parent, reset, FALSE);
887 } else {
888 nr_arena_request_update (item->arena, item);
889 }
890 }
891 }
893 void
894 nr_arena_item_request_render (NRArenaItem *item)
895 {
896 nr_return_if_fail (item != NULL);
897 nr_return_if_fail (NR_IS_ARENA_ITEM (item));
899 nr_arena_request_render_rect (item->arena, &item->bbox);
900 }
902 /* Public */
904 NRArenaItem *
905 nr_arena_item_unparent (NRArenaItem *item)
906 {
907 nr_return_val_if_fail (item != NULL, NULL);
908 nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NULL);
910 nr_arena_item_request_render (item);
912 if (item->parent) {
913 nr_arena_item_remove_child (item->parent, item);
914 }
916 return NULL;
917 }
919 void
920 nr_arena_item_append_child (NRArenaItem *parent, NRArenaItem *child)
921 {
922 nr_return_if_fail (parent != NULL);
923 nr_return_if_fail (NR_IS_ARENA_ITEM (parent));
924 nr_return_if_fail (child != NULL);
925 nr_return_if_fail (NR_IS_ARENA_ITEM (child));
926 nr_return_if_fail (parent->arena == child->arena);
927 nr_return_if_fail (child->parent == NULL);
928 nr_return_if_fail (child->prev == NULL);
929 nr_return_if_fail (child->next == NULL);
931 nr_arena_item_add_child (parent, child, nr_arena_item_last_child (parent));
932 }
934 void
935 nr_arena_item_set_transform (NRArenaItem *item, NR::Matrix const &transform)
936 {
937 NRMatrix const t (transform);
938 nr_arena_item_set_transform (item, &t);
939 }
941 void
942 nr_arena_item_set_transform (NRArenaItem *item, NRMatrix const *transform)
943 {
944 nr_return_if_fail (item != NULL);
945 nr_return_if_fail (NR_IS_ARENA_ITEM (item));
947 if (!transform && !item->transform)
948 return;
950 const NRMatrix *md = (item->transform) ? item->transform : &NR_MATRIX_IDENTITY;
951 const NRMatrix *ms = (transform) ? transform : &NR_MATRIX_IDENTITY;
953 if (!NR_MATRIX_DF_TEST_CLOSE (md, ms, NR_EPSILON)) {
954 nr_arena_item_request_render (item);
955 if (!transform || nr_matrix_test_identity (transform, NR_EPSILON)) {
956 /* Set to identity affine */
957 item->transform = NULL;
958 } else {
959 if (!item->transform)
960 item->transform = new (GC::ATOMIC) NRMatrix ();
961 *item->transform = *transform;
962 }
963 nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
964 }
965 }
967 void
968 nr_arena_item_set_opacity (NRArenaItem *item, double opacity)
969 {
970 nr_return_if_fail (item != NULL);
971 nr_return_if_fail (NR_IS_ARENA_ITEM (item));
973 nr_arena_item_request_render (item);
975 item->opacity = (unsigned int) (opacity * 255.9999);
976 }
978 void
979 nr_arena_item_set_sensitive (NRArenaItem *item, unsigned int sensitive)
980 {
981 nr_return_if_fail (item != NULL);
982 nr_return_if_fail (NR_IS_ARENA_ITEM (item));
984 /* fixme: mess with pick/repick... */
986 item->sensitive = sensitive;
987 }
989 void
990 nr_arena_item_set_visible (NRArenaItem *item, unsigned int visible)
991 {
992 nr_return_if_fail (item != NULL);
993 nr_return_if_fail (NR_IS_ARENA_ITEM (item));
995 item->visible = visible;
997 nr_arena_item_request_render (item);
998 }
1000 void
1001 nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip)
1002 {
1003 nr_return_if_fail (item != NULL);
1004 nr_return_if_fail (NR_IS_ARENA_ITEM (item));
1005 nr_return_if_fail (!clip || NR_IS_ARENA_ITEM (clip));
1007 if (clip != item->clip) {
1008 nr_arena_item_request_render (item);
1009 if (item->clip)
1010 item->clip = nr_arena_item_detach (item, item->clip);
1011 if (clip)
1012 item->clip = nr_arena_item_attach (item, clip, NULL, NULL);
1013 nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
1014 }
1015 }
1017 void
1018 nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask)
1019 {
1020 nr_return_if_fail (item != NULL);
1021 nr_return_if_fail (NR_IS_ARENA_ITEM (item));
1022 nr_return_if_fail (!mask || NR_IS_ARENA_ITEM (mask));
1024 if (mask != item->mask) {
1025 nr_arena_item_request_render (item);
1026 if (item->mask)
1027 item->mask = nr_arena_item_detach (item, item->mask);
1028 if (mask)
1029 item->mask = nr_arena_item_attach (item, mask, NULL, NULL);
1030 nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
1031 }
1032 }
1034 void
1035 nr_arena_item_set_order (NRArenaItem *item, int order)
1036 {
1037 nr_return_if_fail (item != NULL);
1038 nr_return_if_fail (NR_IS_ARENA_ITEM (item));
1040 if (!item->parent)
1041 return;
1043 NRArenaItem *children = nr_arena_item_children (item->parent);
1045 NRArenaItem *ref = NULL;
1046 int pos = 0;
1047 for (NRArenaItem *child = children; child != NULL; child = child->next) {
1048 if (pos >= order)
1049 break;
1050 if (child != item) {
1051 ref = child;
1052 pos += 1;
1053 }
1054 }
1056 nr_arena_item_set_child_position (item->parent, item, ref);
1057 }
1059 /** Returns a background image for use with filter effects. */
1060 NRPixBlock *
1061 nr_arena_item_get_background (NRArenaItem const *item, int depth)
1062 {
1063 NRPixBlock *pb;
1064 if (!item->background_pb)
1065 return NULL;
1066 if (item->background_new) {
1067 pb = new NRPixBlock ();
1068 nr_pixblock_setup_fast (pb, item->background_pb->mode,
1069 item->background_pb->area.x0,
1070 item->background_pb->area.y0,
1071 item->background_pb->area.x1,
1072 item->background_pb->area.y1, true);
1073 if (pb->data.px == NULL) // allocation failed
1074 return NULL;
1075 } else if (item->parent) {
1076 pb = nr_arena_item_get_background (item->parent, depth + 1);
1077 } else
1078 return NULL;
1080 if (depth > 0)
1081 nr_blit_pixblock_pixblock (pb, item->background_pb);
1083 return pb;
1084 }
1086 /* Helpers */
1088 NRArenaItem *
1089 nr_arena_item_attach (NRArenaItem *parent, NRArenaItem *child,
1090 NRArenaItem *prev, NRArenaItem *next)
1091 {
1092 nr_return_val_if_fail (parent != NULL, NULL);
1093 nr_return_val_if_fail (NR_IS_ARENA_ITEM (parent), NULL);
1094 nr_return_val_if_fail (child != NULL, NULL);
1095 nr_return_val_if_fail (NR_IS_ARENA_ITEM (child), NULL);
1096 nr_return_val_if_fail (child->parent == NULL, NULL);
1097 nr_return_val_if_fail (child->prev == NULL, NULL);
1098 nr_return_val_if_fail (child->next == NULL, NULL);
1099 nr_return_val_if_fail (!prev || NR_IS_ARENA_ITEM (prev), NULL);
1100 nr_return_val_if_fail (!prev || (prev->parent == parent), NULL);
1101 nr_return_val_if_fail (!prev || (prev->next == next), NULL);
1102 nr_return_val_if_fail (!next || NR_IS_ARENA_ITEM (next), NULL);
1103 nr_return_val_if_fail (!next || (next->parent == parent), NULL);
1104 nr_return_val_if_fail (!next || (next->prev == prev), NULL);
1106 child->parent = parent;
1107 child->prev = prev;
1108 child->next = next;
1110 if (prev)
1111 prev->next = child;
1112 if (next)
1113 next->prev = child;
1115 return child;
1116 }
1118 NRArenaItem *
1119 nr_arena_item_detach (NRArenaItem *parent, NRArenaItem *child)
1120 {
1121 nr_return_val_if_fail (parent != NULL, NULL);
1122 nr_return_val_if_fail (NR_IS_ARENA_ITEM (parent), NULL);
1123 nr_return_val_if_fail (child != NULL, NULL);
1124 nr_return_val_if_fail (NR_IS_ARENA_ITEM (child), NULL);
1125 nr_return_val_if_fail (child->parent == parent, NULL);
1127 NRArenaItem *prev = child->prev;
1128 NRArenaItem *next = child->next;
1130 child->parent = NULL;
1131 child->prev = NULL;
1132 child->next = NULL;
1134 if (prev)
1135 prev->next = next;
1136 if (next)
1137 next->prev = prev;
1139 return next;
1140 }
1142 /*
1143 *
1144 * caches
1145 *
1146 */
1148 #ifdef arena_item_tile_cache
1149 typedef struct cache_entry {
1150 int key;
1151 double score;
1152 NRArenaItem *owner;
1153 int th, tv;
1154 int prev, next;
1155 NRPixBlock ipb;
1156 bool hasMask;
1157 NRPixBlock mpb;
1158 } cache_entry;
1160 int hash_max = 2048, hash_fill = 1024;
1162 int *keys = NULL;
1163 int nbCch = 0;
1165 int nbEnt = 0, maxEnt = 0;
1166 cache_entry *entries = NULL;
1168 //#define tile_cache_stats
1169 #ifdef tile_cache_stats
1170 double hits = 0, misses = 0;
1171 int hitMissCount = 0;
1172 #endif
1174 int
1175 hash_that (NRArenaItem *owner, int th, int tv)
1176 {
1177 int res = GPOINTER_TO_INT (owner);
1178 res *= 17;
1179 res += th;
1180 res *= 59;
1181 res += tv;
1182 res *= 217;
1183 if (res < 0)
1184 res = -res;
1185 res %= hash_max;
1186 return res;
1187 }
1189 bool
1190 test_cache (NRArenaItem *owner, int th, int tv, NRPixBlock & ipb,
1191 NRPixBlock & mpb, bool & hasMask)
1192 {
1193 if (keys == NULL) {
1194 hash_max = prefs_get_int_attribute ("options.arenatilescachesize", "value", 2048);
1195 hash_fill = (hash_max * 3) / 4;
1196 keys = (int *) malloc (hash_max * sizeof (int));
1197 for (int i = 0; i < hash_max; i++)
1198 keys[i] = -1;
1199 }
1200 int key = hash_that (owner, th, tv);
1201 if (keys[key] < 0) {
1202 #ifdef tile_cache_stats
1203 misses += 1.0;
1204 #endif
1205 return false;
1206 }
1207 int cur = keys[key];
1208 while (cur >= 0 && cur < nbEnt) {
1209 if (entries[cur].owner == owner && entries[cur].th == th
1210 && entries[cur].tv == tv) {
1211 hasMask = entries[cur].hasMask;
1212 ipb = entries[cur].ipb;
1213 mpb = entries[cur].mpb;
1214 #ifdef tile_cache_stats
1215 hits += 1.0;
1216 #endif
1217 return true;
1218 }
1219 cur = entries[cur].next;
1220 }
1221 #ifdef tile_cache_stats
1222 misses += 1.0;
1223 #endif
1224 return false;
1225 }
1227 void
1228 remove_one_cache (int no)
1229 {
1230 if (no < 0 || no >= nbEnt)
1231 return;
1233 nr_pixblock_release (&entries[no].ipb);
1234 if (entries[no].hasMask)
1235 nr_pixblock_release (&entries[no].mpb);
1237 if (entries[no].prev >= 0)
1238 entries[entries[no].prev].next = entries[no].next;
1239 if (entries[no].next >= 0)
1240 entries[entries[no].next].prev = entries[no].prev;
1241 if (entries[no].prev < 0)
1242 keys[entries[no].key] = entries[no].next;
1243 entries[no].prev = entries[no].next = entries[no].key = -1;
1245 if (no == nbEnt - 1) {
1246 nbEnt--;
1247 return;
1248 }
1249 entries[no] = entries[--nbEnt];
1250 if (entries[no].prev >= 0)
1251 entries[entries[no].prev].next = no;
1252 if (entries[no].next >= 0)
1253 entries[entries[no].next].prev = no;
1254 if (entries[no].prev < 0)
1255 keys[entries[no].key] = no;
1256 }
1258 void
1259 remove_caches (NRArenaItem *owner)
1260 {
1261 if (keys == NULL) {
1262 hash_max = prefs_get_int_attribute ("options.arenatilescachesize", "value", 2048);
1263 hash_fill = (hash_max * 3) / 4;
1264 keys = (int *) malloc (hash_max * sizeof (int));
1265 for (int i = 0; i < hash_max; i++)
1266 keys[i] = -1;
1267 }
1268 for (int i = nbEnt - 1; i >= 0; i--) {
1269 if (entries[i].owner == owner) {
1270 remove_one_cache (i);
1271 }
1272 }
1273 }
1274 void
1275 age_cache (void)
1276 {
1277 for (int i = 0; i < nbEnt; i++)
1278 entries[i].score *= 0.95;
1279 }
1281 bool
1282 insert_cache (NRArenaItem *owner, int th, int tv, NRPixBlock *ipb,
1283 NRPixBlock *mpb, double activity, double duration)
1284 {
1285 if (keys == NULL) {
1286 hash_max = prefs_get_int_attribute ("options.arenatilescachesize", "value", 2048);
1287 hash_fill = (hash_max * 3) / 4;
1288 keys = (int *) malloc (hash_max * sizeof (int));
1289 for (int i = 0; i < hash_max; i++)
1290 keys[i] = -1;
1291 }
1292 for (int i = 0; i < nbEnt; i++)
1293 entries[i].score *= 0.95;
1294 #ifdef tile_cache_stats
1295 hits *= 0.95;
1296 misses *= 0.95;
1297 hitMissCount++;
1298 if (hitMissCount > 100) {
1299 hitMissCount = 0;
1300 printf ("hit/miss = %f used/total=%i/%i\n", (misses > 0.001) ? hits / misses : 100000.0, nbEnt, hash_max); // localizing ok
1301 }
1302 #endif
1303 int key = hash_that (owner, th, tv);
1304 double nScore = /*activity* */ duration;
1306 if (keys[key] >= 0) {
1307 int cur = keys[key];
1308 while (cur >= 0 && cur < nbEnt) {
1309 if (entries[cur].owner == owner && entries[cur].th == th
1310 && entries[cur].tv == tv) {
1311 remove_one_cache (cur);
1312 break;
1313 }
1314 cur = entries[cur].next;
1315 }
1316 }
1318 bool doAdd = false;
1319 if (nbEnt < hash_fill) {
1320 doAdd = true;
1321 } else {
1322 double worstS = entries[0].score;
1323 int worstE = 0;
1324 for (int i = 1; i < nbEnt; i++) {
1325 if (entries[i].score < worstS) {
1326 worstS = entries[i].score;
1327 worstE = i;
1328 }
1329 }
1330 if (worstS < nScore) {
1331 doAdd = true;
1332 remove_one_cache (worstE);
1333 }
1334 }
1335 if (doAdd == false)
1336 return false;
1337 if (nbEnt >= maxEnt) {
1338 maxEnt = 2 * nbEnt + 1;
1339 entries = (cache_entry *) realloc (entries, maxEnt * sizeof (cache_entry));
1340 }
1341 entries[nbEnt].key = key;
1342 entries[nbEnt].score = nScore;
1343 entries[nbEnt].owner = owner;
1344 entries[nbEnt].th = th;
1345 entries[nbEnt].tv = tv;
1346 entries[nbEnt].prev = entries[nbEnt].next = -1;
1347 entries[nbEnt].ipb = *ipb;
1348 if (mpb) {
1349 entries[nbEnt].hasMask = true;
1350 entries[nbEnt].mpb = *mpb;
1351 } else {
1352 entries[nbEnt].hasMask = false;
1353 }
1354 entries[nbEnt].next = keys[key];
1355 if (entries[nbEnt].next >= 0)
1356 entries[entries[nbEnt].next].prev = nbEnt;
1357 keys[key] = nbEnt;
1359 nbEnt++;
1360 return true;
1361 }
1362 #endif
1364 /*
1365 Local Variables:
1366 mode:c++
1367 c-file-style:"stroustrup"
1368 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1369 indent-tabs-mode:nil
1370 fill-column:99
1371 End:
1372 */
1373 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :