diff options
author | David Robillard <d@drobilla.net> | 2013-12-27 00:38:17 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2013-12-27 00:38:17 +0000 |
commit | 76298e353df88996de4b423f3090811723b73d37 (patch) | |
tree | 307edcd3cebb36acf404af5ffb8aaad48de72cb3 /src | |
parent | f3d304f86be2d4639ba61267a1ca861900fb9d7d (diff) | |
download | ganv-76298e353df88996de4b423f3090811723b73d37.tar.gz ganv-76298e353df88996de4b423f3090811723b73d37.tar.bz2 ganv-76298e353df88996de4b423f3090811723b73d37.zip |
Performance improvements.
git-svn-id: http://svn.drobilla.net/lad/trunk/ganv@5214 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r-- | src/Canvas.cpp | 66 | ||||
-rw-r--r-- | src/box.c | 21 | ||||
-rw-r--r-- | src/canvas-base.c | 156 | ||||
-rw-r--r-- | src/circle.c | 6 | ||||
-rw-r--r-- | src/edge.c | 32 | ||||
-rw-r--r-- | src/fdgl.hpp | 3 | ||||
-rw-r--r-- | src/ganv-private.h | 13 | ||||
-rw-r--r-- | src/group.c | 36 | ||||
-rw-r--r-- | src/port.c | 19 | ||||
-rw-r--r-- | src/text.c | 3 |
10 files changed, 179 insertions, 176 deletions
diff --git a/src/Canvas.cpp b/src/Canvas.cpp index 593fe07..4d59b6f 100644 --- a/src/Canvas.cpp +++ b/src/Canvas.cpp @@ -173,6 +173,8 @@ struct GanvCanvasImpl { } gboolean layout_iteration(); + gboolean layout_calculate(double dur, bool update); + #endif GanvItem* root() { @@ -714,10 +716,10 @@ get_region(const GanvNode* node) Region reg; reg.area.x = x2 - x1; reg.area.y = y2 - y1; - reg.pos.x = x1 + (reg.area.x / 2.0); - reg.pos.y = y1 + (reg.area.y / 2.0); + reg.pos.x = GANV_ITEM(node)->x + (reg.area.x / 2.0); + reg.pos.y = GANV_ITEM(node)->y + (reg.area.y / 2.0); - ganv_item_i2w(GANV_ITEM(node), ®.pos.x, ®.pos.y); + // No need for i2w here since we only care about top-level items return reg; } @@ -731,10 +733,34 @@ apply_force(GanvNode* a, GanvNode* b, const Vector& f) gboolean GanvCanvasImpl::layout_iteration() { - static const double SPRING_K = 14.0; + static const double T_PER_US = .00001; // Sym time per real microsecond + + static uint64_t prev = 0; // Previous iteration time + + const uint64_t now = g_get_monotonic_time(); + const double time_to_run = std::min((now - prev) * T_PER_US, 1.0); + + prev = now; + + const double QUANTUM = 0.1; + double sym_time = 0.0; + while (sym_time + QUANTUM < time_to_run) { + if (!layout_calculate(QUANTUM, FALSE)) { + break; + } + sym_time += QUANTUM; + } + + return layout_calculate(QUANTUM, TRUE); +} + +gboolean +GanvCanvasImpl::layout_calculate(double dur, bool update) +{ + static const double SPRING_K = 28.0; // A light directional force to push sources to the top left - static const double DIR_MAGNITUDE = -600.0; + static const double DIR_MAGNITUDE = -1200.0; Vector dir = { 0.0, 0.0 }; switch (_gcanvas->direction) { case GANV_DIRECTION_RIGHT: dir.x = DIR_MAGNITUDE; break; @@ -759,9 +785,11 @@ GanvCanvasImpl::layout_iteration() head->impl->has_in_edges = TRUE; tail->impl->has_out_edges = TRUE; - const Vector tpos = { edge->impl->coords.x1, edge->impl->coords.y1 }; - const Vector hpos = { edge->impl->coords.x2, edge->impl->coords.y2 }; + GanvEdgeCoords coords; + ganv_edge_get_coords(edge, &coords); + const Vector tpos = { coords.x1, coords.y1 }; + const Vector hpos = { coords.x2, coords.y2 }; apply_force(tail, head, edge_force(dir, hpos, tpos, 0.0001, SPRING_K)); } @@ -827,8 +855,7 @@ GanvCanvasImpl::layout_iteration() GanvNode* const node = GANV_NODE(*i); - static const float dur = 0.1; // Time duration - static const float damp = 0.3; // Velocity damping + static const float damp = 0.4; // Velocity damping const bool has_edges = (node->impl->has_in_edges || node->impl->has_out_edges); @@ -851,7 +878,7 @@ GanvCanvasImpl::layout_iteration() // Update position const Vector dpos = vec_mult(node->impl->vel, dur); - if (ganv_item_move(GANV_ITEM(node), dpos.x, dpos.y)) { + if (ganv_item_move_update(GANV_ITEM(node), dpos.x, dpos.y, update)) { ++n_moved; } } @@ -863,17 +890,15 @@ GanvCanvasImpl::layout_iteration() node->impl->has_out_edges = FALSE; } - if (n_moved == 0) { - return FALSE; // Stabilized, we're done - } - - // Now update edge positions to reflect new node positions - FOREACH_EDGE(_edges, i) { - GanvEdge* const edge = *i; - ganv_edge_update_location(edge); + if (update) { + // Now update edge positions to reflect new node positions + FOREACH_EDGE(_edges, i) { + GanvEdge* const edge = *i; + ganv_edge_update_location(edge); + } } - return TRUE; + return n_moved > 0; } #endif // GANV_FDGL @@ -1662,7 +1687,7 @@ GanvCanvasImpl::contents_changed() if (!_layout_idle_id) { _layout_idle_id = g_timeout_add_full( G_PRIORITY_DEFAULT_IDLE, - 66, + 33, on_layout_timeout, this, on_layout_done); @@ -2129,6 +2154,7 @@ ganv_canvas_set_direction(GanvCanvas* canvas, GanvDirection dir) if (canvas->direction != dir) { canvas->direction = dir; ganv_canvas_for_each_node(canvas, set_node_direction, &dir); + ganv_canvas_contents_changed(canvas); } } @@ -155,8 +155,7 @@ ganv_box_request_redraw(GanvItem* item, if (!world) { // Convert from parent-relative coordinates to world coordinates - ganv_item_i2w(item, &x1, &y1); - ganv_item_i2w(item, &x2, &y2); + ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2); } ganv_canvas_base_request_redraw(item->canvas, x1, y1, x2, y2); @@ -165,8 +164,7 @@ ganv_box_request_redraw(GanvItem* item, static void coords_i2w(GanvItem* item, GanvBoxCoords* coords) { - ganv_item_i2w(item, &coords->x1, &coords->y1); - ganv_item_i2w(item, &coords->x2, &coords->y2); + ganv_item_i2w_pair(item, &coords->x1, &coords->y1, &coords->x2, &coords->y2); } static void @@ -177,8 +175,7 @@ ganv_box_bounds(GanvItem* item, // Note this will not be correct if children are outside the box bounds GanvBox* box = GANV_BOX(item); ganv_box_bounds_item(&box->impl->coords, x1, y1, x2, y2); - ganv_item_i2w(item, x1, y1); - ganv_item_i2w(item, x2, y2); + ganv_item_i2w_pair(item, x1, y1, x2, y2); } static void @@ -224,8 +221,7 @@ ganv_box_draw(GanvItem* item, double y1 = impl->coords.y1; double x2 = impl->coords.x2; double y2 = impl->coords.y2; - ganv_item_i2w(item, &x1, &y1); - ganv_item_i2w(item, &x2, &y2); + ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2); double dash_length, border_color, fill_color; ganv_node_get_draw_properties( @@ -233,11 +229,11 @@ ganv_box_draw(GanvItem* item, double r, g, b, a; - double degrees = G_PI / 180.0; + static const double degrees = G_PI / 180.0; for (int i = (impl->coords.stacked ? 1 : 0); i >= 0; --i) { - const double x = 0 - (STACKED_OFFSET * i); - const double y = 0 - (STACKED_OFFSET * i); + const double x = 0.0 - (STACKED_OFFSET * i); + const double y = 0.0 - (STACKED_OFFSET * i); if (impl->radius_tl == 0.0 && impl->radius_tr == 0.0 && impl->radius_br == 0.0 && impl->radius_bl == 0.0) { @@ -341,8 +337,7 @@ ganv_box_is_within(const GanvNode* self, "y2", &by2, NULL); - ganv_item_i2w(GANV_ITEM(self), &bx1, &by1); - ganv_item_i2w(GANV_ITEM(self), &bx2, &by2); + ganv_item_i2w_pair(GANV_ITEM(self), &bx1, &by1, &bx2, &by2); return ( bx1 >= x1 && by2 >= y1 diff --git a/src/canvas-base.c b/src/canvas-base.c index 544b558..d316f16 100644 --- a/src/canvas-base.c +++ b/src/canvas-base.c @@ -415,14 +415,8 @@ ganv_item_lower(GanvItem* item) --item->layer; } -/** - * ganv_item_move: - * @item: A canvas item. - * @dx: Horizontal offset. - * @dy: Vertical offset. - **/ gboolean -ganv_item_move(GanvItem* item, double dx, double dy) +ganv_item_move_update(GanvItem* item, double dx, double dy, gboolean update) { if (item == NULL || !GANV_IS_ITEM(item)) { return FALSE; @@ -442,6 +436,33 @@ ganv_item_move(GanvItem* item, double dx, double dy) item->y = MIN_COORD; } + const gboolean moved = (lrint(old_x) != lrint(item->x) || + lrint(old_y) != lrint(item->y)); + + if (update) { + ganv_item_request_update(item); + item->canvas->need_repick = TRUE; + } + + return moved; +} + +/** + * ganv_item_move: + * @item: A canvas item. + * @dx: Horizontal offset. + * @dy: Vertical offset. + **/ +gboolean +ganv_item_move(GanvItem* item, double dx, double dy) +{ + const double old_x = item->x; + const double old_y = item->y; + + if (!ganv_item_move_update(item, dx, dy, FALSE)) { + return FALSE; + } + if (lrint(old_x) != lrint(item->x) || lrint(old_y) != lrint(item->y)) { ganv_item_request_update(item); @@ -610,6 +631,20 @@ ganv_item_w2i(GanvItem* item, double* x, double* y) cairo_matrix_transform_point(&matrix, x, y); } +void +ganv_item_i2w_offset(GanvItem* item, double* px, double* py) +{ + double x = 0.0; + double y = 0.0; + while (item) { + x += item->x; + y += item->y; + item = item->parent; + } + *px = x; + *py = y; +} + /** * ganv_item_i2w: * @item: A canvas item. @@ -622,14 +657,29 @@ ganv_item_w2i(GanvItem* item, double* x, double* y) void ganv_item_i2w(GanvItem* item, double* x, double* y) { - g_return_if_fail(GANV_IS_ITEM(item)); + /*g_return_if_fail(GANV_IS_ITEM(item)); g_return_if_fail(x != NULL); - g_return_if_fail(y != NULL); + g_return_if_fail(y != NULL);*/ - cairo_matrix_t matrix; - ganv_item_i2w_affine(item, &matrix); + double off_x; + double off_y; + ganv_item_i2w_offset(item, &off_x, &off_y); - cairo_matrix_transform_point(&matrix, x, y); + *x += off_x; + *y += off_y; +} + +void +ganv_item_i2w_pair(GanvItem* item, double* x1, double* y1, double* x2, double* y2) +{ + double off_x; + double off_y; + ganv_item_i2w_offset(item, &off_x, &off_y); + + *x1 += off_x; + *y1 += off_y; + *x2 += off_x; + *y2 += off_y; } /** @@ -720,41 +770,19 @@ ganv_item_grab_focus(GanvItem* item) void ganv_item_get_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2) { - double ix1, iy1, ix2, iy2; - g_return_if_fail(GANV_IS_ITEM(item)); - ix1 = iy1 = ix2 = iy2 = 0.0; - - /* Get the item's bounds in its coordinate system */ - if (GANV_ITEM_GET_CLASS(item)->bounds) { - (*GANV_ITEM_GET_CLASS(item)->bounds)(item, &ix1, &iy1, &ix2, &iy2); - } - - /* Make the bounds relative to the item's parent coordinate system */ - - ix1 -= item->x; - iy1 -= item->y; - ix2 -= item->x; - iy2 -= item->y; - - /* Return the values */ - - if (x1) { - *x1 = ix1; - } - - if (y1) { - *y1 = iy1; - } - - if (x2) { - *x2 = ix2; - } - - if (y2) { - *y2 = iy2; + // Get bounds from item class + (*GANV_ITEM_GET_CLASS(item)->bounds)(item, x1, y1, x2, y2); + + // Make bounds relative to the item's parent coordinate system + *x1 -= item->x; + *y1 -= item->y; + *x2 -= item->x; + *y2 -= item->y; + } else { + *x1 = *y1 = *x2 = *y2 = 0.0; } } @@ -792,11 +820,6 @@ ganv_item_request_update(GanvItem* item) /*** GanvCanvasBase ***/ -enum { - DRAW_BACKGROUND, - LAST_SIGNAL -}; - static void ganv_canvas_base_destroy(GtkObject* object); static void ganv_canvas_base_map(GtkWidget* widget); static void ganv_canvas_base_unmap(GtkWidget* widget); @@ -821,17 +844,9 @@ static gint ganv_canvas_base_focus_in(GtkWidget* widget, static gint ganv_canvas_base_focus_out(GtkWidget* widget, GdkEventFocus* event); static void ganv_canvas_base_request_update_real(GanvCanvasBase* canvas); -static void ganv_canvas_base_draw_background(GanvCanvasBase* canvas, - GdkDrawable* drawable, - int x, - int y, - int width, - int height); static GtkLayoutClass* canvas_parent_class; -static guint canvas_signals[LAST_SIGNAL]; - enum { PROP_FOCUSED_ITEM = 1 }; @@ -906,23 +921,12 @@ ganv_canvas_base_class_init(GanvCanvasBaseClass* klass) widget_class->focus_out_event = ganv_canvas_base_focus_out; widget_class->scroll_event = ganv_canvas_base_scroll; - klass->draw_background = ganv_canvas_base_draw_background; - klass->request_update = ganv_canvas_base_request_update_real; + klass->request_update = ganv_canvas_base_request_update_real; g_object_class_install_property(gobject_class, PROP_FOCUSED_ITEM, g_param_spec_object("focused_item", NULL, NULL, GANV_TYPE_ITEM, (G_PARAM_READABLE | G_PARAM_WRITABLE))); - - canvas_signals[DRAW_BACKGROUND] - = g_signal_new("draw_background", - G_TYPE_FROM_CLASS(object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GanvCanvasBaseClass, draw_background), - NULL, NULL, - ganv_marshal_VOID__OBJECT_INT_INT_INT_INT, - G_TYPE_NONE, 5, GDK_TYPE_DRAWABLE, - G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); } /* Callback used when the root item of a canvas is destroyed. The user should @@ -1899,20 +1903,6 @@ paint(GanvCanvasBase* canvas) } static void -ganv_canvas_base_draw_background(GanvCanvasBase* canvas, GdkDrawable* drawable, - int x, int y, int width, int height) -{ - /* By default, we use the style background. */ - gdk_gc_set_foreground(canvas->pixmap_gc, - >K_WIDGET(canvas)->style->bg[GTK_STATE_NORMAL]); - gdk_draw_rectangle(drawable, - canvas->pixmap_gc, - TRUE, - 0, 0, - width, height); -} - -static void do_update(GanvCanvasBase* canvas) { /* Cause the update if necessary */ diff --git a/src/circle.c b/src/circle.c index 59a805b..54f28cb 100644 --- a/src/circle.c +++ b/src/circle.c @@ -231,8 +231,7 @@ request_redraw(GanvItem* item, if (!world) { // Convert from parent-relative coordinates to world coordinates - ganv_item_i2w(item, &x1, &y1); - ganv_item_i2w(item, &x2, &y2); + ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2); } ganv_canvas_base_request_redraw(item->canvas, x1, y1, x2, y2); @@ -264,8 +263,7 @@ ganv_circle_bounds(GanvItem* item, double* x2, double* y2) { ganv_circle_bounds_item(item, x1, y1, x2, y2); - ganv_item_i2w(item, x1, y1); - ganv_item_i2w(item, x2, y2); + ganv_item_i2w_pair(item, x1, y1, x2, y2); } static void @@ -249,21 +249,11 @@ ganv_edge_bounds(GanvItem* item, } } -static void -ganv_edge_update(GanvItem* item, int flags) +void +ganv_edge_get_coords(const GanvEdge* edge, GanvEdgeCoords* coords) { - GanvEdge* edge = GANV_EDGE(item); GanvEdgeImpl* impl = edge->impl; - if (parent_class->update) { - (*parent_class->update)(item, flags); - } - - // Request redraw of old location - ganv_edge_request_redraw(item->canvas, &impl->old_coords); - - // Calculate new coordinates from tail and head - GanvEdgeCoords* coords = &impl->coords; GANV_NODE_GET_CLASS(impl->tail)->tail_vector( impl->tail, impl->head, &coords->x1, &coords->y1, &coords->cx1, &coords->cy1); @@ -273,6 +263,7 @@ ganv_edge_update(GanvItem* item, int flags) const double dx = coords->x2 - coords->x1; const double dy = coords->y2 - coords->y1; + coords->handle_x = coords->x1 + (dx / 2.0); coords->handle_y = coords->y1 + (dy / 2.0); @@ -280,6 +271,23 @@ ganv_edge_update(GanvItem* item, int flags) coords->cy1 = coords->y1 + (coords->cy1 * (ceil(fabs(dy)) / 4.0)); coords->cx2 = coords->x2 + (coords->cx2 * (ceil(fabs(dx)) / 4.0)); coords->cy2 = coords->y2 + (coords->cy2 * (ceil(fabs(dy)) / 4.0)); +} + +static void +ganv_edge_update(GanvItem* item, int flags) +{ + GanvEdge* edge = GANV_EDGE(item); + GanvEdgeImpl* impl = edge->impl; + + if (parent_class->update) { + (*parent_class->update)(item, flags); + } + + // Request redraw of old location + ganv_edge_request_redraw(item->canvas, &impl->old_coords); + + // Calculate new coordinates from tail and head + ganv_edge_get_coords(edge, &impl->coords); // Update old coordinates impl->old_coords = impl->coords; diff --git a/src/fdgl.hpp b/src/fdgl.hpp index 084ebed..704eb4f 100644 --- a/src/fdgl.hpp +++ b/src/fdgl.hpp @@ -16,8 +16,7 @@ #include <float.h> #include <math.h> -static const double SPRING_K = 10.0; -static const double CHARGE_KE = 50000000.0; +static const double CHARGE_KE = 100000000.0; struct Region { Vector pos; diff --git a/src/ganv-private.h b/src/ganv-private.h index 272381d..5540898 100644 --- a/src/ganv-private.h +++ b/src/ganv-private.h @@ -105,7 +105,6 @@ struct _GanvNodeImpl { double border_width; guint fill_color; guint border_color; - guint layer; gboolean can_tail; gboolean can_head; gboolean is_source; @@ -199,11 +198,23 @@ ganv_canvas_port_event(GanvCanvas* canvas, GdkEvent* event); void +ganv_item_i2w_offset(GanvItem* item, double* px, double* py); + +void +ganv_item_i2w_pair(GanvItem* item, double* x1, double* y1, double* x2, double* y2); + +gboolean +ganv_item_move_update(GanvItem* item, double dx, double dy, gboolean update); + +void ganv_item_invoke_update(GanvItem* item, int flags); /* Edge */ void +ganv_edge_get_coords(const GanvEdge* edge, GanvEdgeCoords* coords); + +void ganv_edge_request_redraw(GanvCanvasBase* canvas, const GanvEdgeCoords* coords); diff --git a/src/group.c b/src/group.c index 8624a90..75183ca 100644 --- a/src/group.c +++ b/src/group.c @@ -195,19 +195,6 @@ ganv_group_unmap(GanvItem* item) (*group_parent_class->unmap)(item); } -static gint -item_layer_cmp(const void* a, const void* b, void* user_data) -{ - const GanvItem* ia = (const GanvItem*)a; - const GanvItem* ib = (const GanvItem*)b; - if (ia->layer == ib->layer) { - // Same layer, order in a quasi-cascade - return (ia->x1 - ib->x1) + (ia->y1 - ib->y1); - } else { - return ia->layer - ib->layer; - } -} - static void ganv_group_draw(GanvItem* item, cairo_t* cr, int x, int y, int width, int height) @@ -223,7 +210,8 @@ ganv_group_draw(GanvItem* item, cairo_t* cr, cairo_rectangle(cr, x, y, width, height); cairo_fill(cr); - GSequence* items = g_sequence_new(NULL); + // TODO: Layered drawing + for (list = group->item_list; list; list = list->next) { child = (GanvItem*)list->data; @@ -231,27 +219,13 @@ ganv_group_draw(GanvItem* item, cairo_t* cr, && ((child->x1 < (x + width)) && (child->y1 < (y + height)) && (child->x2 > x) - && (child->y2 > y))) - || ((GTK_OBJECT_FLAGS(child) & GANV_ITEM_ALWAYS_REDRAW) - && (child->x1 < child->canvas->redraw_x2) - && (child->y1 < child->canvas->redraw_y2) - && (child->x2 > child->canvas->redraw_x1) - && (child->y2 > child->canvas->redraw_y2))) { + && (child->y2 > y)))) { if (GANV_ITEM_GET_CLASS(child)->draw) { - g_sequence_insert_sorted(items, child, item_layer_cmp, NULL); + (*GANV_ITEM_GET_CLASS(child)->draw)( + child, cr, x, y, width, height); } } } - - for (GSequenceIter* i = g_sequence_get_begin_iter(items); - !g_sequence_iter_is_end(i); - i = g_sequence_iter_next(i)) { - child = (GanvItem*)g_sequence_get(i); - (*GANV_ITEM_GET_CLASS(child)->draw)( - child, cr, x, y, width, height); - } - - g_sequence_free(items); } static double @@ -138,6 +138,10 @@ ganv_port_draw(GanvItem* item, GANV_ITEM_GET_CLASS(rect)->draw(rect, cr, cx, cy, width, height); } + if (!GANV_NODE(port)->impl->show_label) { + return; + } + GanvItem* labels[2] = { GANV_ITEM(GANV_NODE(item)->impl->label), port->impl->control ? GANV_ITEM(port->impl->control->label) : NULL @@ -158,11 +162,12 @@ ganv_port_tail_vector(const GanvNode* self, double* dx, double* dy) { + GanvItem* item = GANV_ITEM(self); GanvPort* port = GANV_PORT(self); GanvCanvas* canvas = GANV_CANVAS(GANV_ITEM(self)->canvas); - double px, py; - g_object_get(G_OBJECT(self), "x", &px, "y", &py, NULL); + const double px = item->x; + const double py = item->y; switch (canvas->direction) { case GANV_DIRECTION_RIGHT: @@ -190,11 +195,12 @@ ganv_port_head_vector(const GanvNode* self, double* dx, double* dy) { + GanvItem* item = GANV_ITEM(self); GanvPort* port = GANV_PORT(self); GanvCanvas* canvas = GANV_CANVAS(GANV_ITEM(self)->canvas); - double px, py; - g_object_get(G_OBJECT(self), "x", &px, "y", &py, NULL); + const double px = item->x; + const double py = item->y; switch (canvas->direction) { case GANV_DIRECTION_RIGHT: @@ -388,10 +394,6 @@ ganv_port_new(GanvModule* module, va_end(args); GanvBox* box = GANV_BOX(port); - box->impl->radius_tl = (is_input ? 0.0 : 4.0); - box->impl->radius_tr = (is_input ? 4.0 : 0.0); - box->impl->radius_br = (is_input ? 4.0 : 0.0); - box->impl->radius_bl = (is_input ? 0.0 : 4.0); box->impl->coords.border_width = 1.0; GanvNode* node = GANV_NODE(port); @@ -472,6 +474,7 @@ void ganv_port_set_value_label(GanvPort* port, const char* str) { + GanvNode* node = GANV_NODE(port); GanvPortImpl* impl = port->impl; if (!impl->control) { return; @@ -229,8 +229,7 @@ ganv_text_bounds(GanvItem* item, double* x2, double* y2) { ganv_text_bounds_item(item, x1, y1, x2, y2); - ganv_item_i2w(item->parent, x1, y1); - ganv_item_i2w(item->parent, x2, y2); + ganv_item_i2w_pair(item->parent, x1, y1, x2, y2); } static void |