static unsigned int nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset) { unsigned int newstate; NRArenaGroup *group = NR_ARENA_GROUP (item); unsigned int beststate = NR_ARENA_ITEM_STATE_ALL; for (NRArenaItem *child = group->children; child != NULL; child = child->next) { NRGC cgc(gc); cgc.transform = group->child_transform * gc->transform; newstate = nr_arena_item_invoke_update (child, area, &cgc, state, reset); beststate = beststate & newstate; } if (beststate & NR_ARENA_ITEM_STATE_BBOX) { nr_rect_l_set_empty (&item->bbox); for (NRArenaItem *child = group->children; child != NULL; child = child->next) { if (child->visible) nr_rect_l_union (&item->bbox, &item->bbox, &child->drawbox); } } return beststate; }
static unsigned int nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset) { NRArenaGroup *group; NRArenaItem *child; unsigned int newstate, beststate; group = NR_ARENA_GROUP (item); beststate = NR_ARENA_ITEM_STATE_ALL; for (child = group->children; child != NULL; child = child->next) { NRGC cgc; nr_matrix_multiply_dfd (&cgc.transform, &group->child_transform, &gc->transform); newstate = nr_arena_item_invoke_update (child, area, &cgc, state, reset); beststate = beststate & newstate; } if (beststate & NR_ARENA_ITEM_STATE_BBOX) { nr_rect_l_set_empty (&item->bbox); for (child = group->children; child != NULL; child = child->next) { nr_rect_l_union (&item->bbox, &item->bbox, &child->bbox); } } return beststate; }
static void sp_canvas_arena_update (SPCanvasItem *item, double *affine, unsigned int flags) { SPCanvasArena *arena; guint reset; arena = SP_CANVAS_ARENA (item); if (((SPCanvasItemClass *) parent_class)->update) (* ((SPCanvasItemClass *) parent_class)->update) (item, affine, flags); memcpy (NR_MATRIX_D_TO_DOUBLE (&arena->gc.transform), affine, 6 * sizeof (double)); if (flags & SP_CANVAS_UPDATE_AFFINE) { reset = NR_ARENA_ITEM_STATE_ALL; } else { reset = NR_ARENA_ITEM_STATE_NONE; } nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_ALL, reset); item->x1 = arena->root->bbox.x0 - 1; item->y1 = arena->root->bbox.y0 - 1; item->x2 = arena->root->bbox.x1 + 1; item->y2 = arena->root->bbox.y1 + 1; if (arena->cursor) { NRArenaItem *new_arena; /* Mess with enter/leave notifiers */ new_arena = nr_arena_item_invoke_pick (arena->root, arena->cx, arena->cy, nr_arena_global_delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; ec.window = GTK_WIDGET (item->canvas)->window; ec.send_event = TRUE; ec.subwindow = ec.window; ec.time = GDK_CURRENT_TIME; ec.x = arena->cx; ec.y = arena->cy; /* fixme: */ if (arena->active) { ec.type = GDK_LEAVE_NOTIFY; sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); } /* fixme: This is not optimal - better track ::destroy (Lauris) */ if (arena->active) nr_object_unref ((NRObject *) arena->active); arena->active = new_arena; if (arena->active) nr_object_ref ((NRObject *) arena->active); if (arena->active) { ec.type = GDK_ENTER_NOTIFY; sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); } } } }
static double sp_canvas_arena_point (SPCanvasItem *item, double x, double y, SPCanvasItem **actual_item) { SPCanvasArena *arena; NRArenaItem *picked; arena = SP_CANVAS_ARENA (item); nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); picked = nr_arena_item_invoke_pick (arena->root, x, y, nr_arena_global_delta, arena->sticky); arena->picked = picked; if (picked) { *actual_item = item; return 0.0; } return 1e18; }
static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) { SPCanvasArena *arena; NRArenaItem *new_arena; gint ret; /* fixme: This sucks, we have to handle enter/leave notifiers */ arena = SP_CANVAS_ARENA (item); ret = FALSE; switch (event->type) { case GDK_ENTER_NOTIFY: if (!arena->cursor) { if (arena->active) { g_warning ("Cursor entered to arena with already active item"); nr_object_unref ((NRObject *) arena->active); } arena->cursor = TRUE; #if 0 gnome_canvas_w2c_d (item->canvas, event->crossing.x, event->crossing.y, &arena->cx, &arena->cy); #else arena->cx = event->crossing.x; arena->cy = event->crossing.y; #endif /* fixme: Not sure abut this, but seems the right thing (Lauris) */ nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); arena->active = nr_arena_item_invoke_pick (arena->root, arena->cx, arena->cy, nr_arena_global_delta, arena->sticky); if (arena->active) nr_object_ref ((NRObject *) arena->active); ret = sp_canvas_arena_send_event (arena, event); } break; case GDK_LEAVE_NOTIFY: if (arena->cursor) { ret = sp_canvas_arena_send_event (arena, event); if (arena->active) nr_object_unref ((NRObject *) arena->active); arena->active = NULL; arena->cursor = FALSE; } break; case GDK_MOTION_NOTIFY: #if 0 gnome_canvas_w2c_d (item->canvas, event->motion.x, event->motion.y, &arena->cx, &arena->cy); #else arena->cx = event->motion.x; arena->cy = event->motion.y; #endif /* fixme: Not sure abut this, but seems the right thing (Lauris) */ nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_PICK, NR_ARENA_ITEM_STATE_NONE); new_arena = nr_arena_item_invoke_pick (arena->root, arena->cx, arena->cy, nr_arena_global_delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; ec.window = event->motion.window; ec.send_event = event->motion.send_event; ec.subwindow = event->motion.window; ec.time = event->motion.time; ec.x = event->motion.x; ec.y = event->motion.y; /* fixme: */ if (arena->active) { ec.type = GDK_LEAVE_NOTIFY; ret = sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); } if (arena->active) nr_object_unref ((NRObject *) arena->active); arena->active = new_arena; if (arena->active) nr_object_ref ((NRObject *) arena->active); if (arena->active) { ec.type = GDK_ENTER_NOTIFY; ret = sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); } } ret = sp_canvas_arena_send_event (arena, event); break; default: /* Just send event */ ret = sp_canvas_arena_send_event (arena, event); break; } return ret; }
static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) { SPCanvasArena *arena; gint bw, bh, sw, sh; gint x, y; arena = SP_CANVAS_ARENA (item); nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER, NR_ARENA_ITEM_STATE_NONE); if (buf->is_bg) { sp_canvas_clear_buffer (buf); buf->is_bg = FALSE; buf->is_buf = TRUE; } bw = buf->rect.x1 - buf->rect.x0; bh = buf->rect.y1 - buf->rect.y0; if ((bw < 1) || (bh < 1)) return; /* 65536 is max cached buffer and we need 4 channels */ if (bw * bh < 16384) { /* We can go with single buffer */ sw = bw; sh = bh; } else if (bw <= 2048) { /* Go with row buffer */ sw = bw; sh = 16384 / bw; } else if (bh <= 2048) { /* Go with column buffer */ sw = 16384 / bh; sh = bh; } else { sw = 128; sh = 128; } /* fixme: RGB transformed bitmap blit is not implemented (Lauris) */ /* And even if it would be, unless it uses MMX there is little reason to go RGB */ #define STRICT_RGBA for (y = buf->rect.y0; y < buf->rect.y1; y += sh) { for (x = buf->rect.x0; x < buf->rect.x1; x += sw) { NRRectL area; #ifdef STRICT_RGBA NRPixBlock pb; #endif NRPixBlock cb; area.x0 = x; area.y0 = y; area.x1 = MIN (x + sw, buf->rect.x1); area.y1 = MIN (y + sh, buf->rect.y1); #ifdef STRICT_RGBA nr_pixblock_setup_fast (&pb, NR_PIXBLOCK_MODE_R8G8B8A8P, area.x0, area.y0, area.x1, area.y1, TRUE); /* fixme: */ pb.empty = FALSE; #endif nr_pixblock_setup_extern (&cb, NR_PIXBLOCK_MODE_R8G8B8, area.x0, area.y0, area.x1, area.y1, buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + 3 * (x - buf->rect.x0), buf->buf_rowstride, FALSE, FALSE); #ifdef STRICT_RGBA nr_arena_item_invoke_render (arena->root, &area, &pb, 0); nr_blit_pixblock_pixblock (&cb, &pb); nr_pixblock_release (&pb); #else nr_arena_item_invoke_render (arena->root, &area, &cb, 0); #endif nr_pixblock_release (&cb); } } }
GdkPixbuf* render_pixbuf(NRArenaItem* root, double scale_factor, const Geom::Rect& dbox, unsigned psize) { NRGC gc(NULL); Geom::Matrix t(Geom::Scale(scale_factor, scale_factor)); nr_arena_item_set_transform(root, t); gc.transform.setIdentity(); nr_arena_item_invoke_update( root, NULL, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE ); /* Item integer bbox in points */ NRRectL ibox; ibox.x0 = (int) floor(scale_factor * dbox.min()[Geom::X] + 0.5); ibox.y0 = (int) floor(scale_factor * dbox.min()[Geom::Y] + 0.5); ibox.x1 = (int) floor(scale_factor * dbox.max()[Geom::X] + 0.5); ibox.y1 = (int) floor(scale_factor * dbox.max()[Geom::Y] + 0.5); /* Find visible area */ int width = ibox.x1 - ibox.x0; int height = ibox.y1 - ibox.y0; int dx = psize; int dy = psize; dx = (dx - width)/2; // watch out for size, since 'unsigned'-'signed' can cause problems if the result is negative dy = (dy - height)/2; NRRectL area; area.x0 = ibox.x0 - dx; area.y0 = ibox.y0 - dy; area.x1 = area.x0 + psize; area.y1 = area.y0 + psize; /* Actual renderable area */ NRRectL ua; ua.x0 = std::max(ibox.x0, area.x0); ua.y0 = std::max(ibox.y0, area.y0); ua.x1 = std::min(ibox.x1, area.x1); ua.y1 = std::min(ibox.y1, area.y1); /* Set up pixblock */ guchar *px = g_new(guchar, 4 * psize * psize); memset(px, 0x00, 4 * psize * psize); /* Render */ NRPixBlock B; nr_pixblock_setup_extern( &B, NR_PIXBLOCK_MODE_R8G8B8A8N, ua.x0, ua.y0, ua.x1, ua.y1, px + 4 * psize * (ua.y0 - area.y0) + 4 * (ua.x0 - area.x0), 4 * psize, FALSE, FALSE ); nr_arena_item_invoke_render(NULL, root, &ua, &B, NR_ARENA_ITEM_RENDER_NO_CACHE ); nr_pixblock_release(&B); GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(px, GDK_COLORSPACE_RGB, TRUE, 8, psize, psize, psize * 4, (GdkPixbufDestroyNotify)g_free, NULL); return pixbuf; }