From 1079b1b4c0331e5d4bd62f3c93349aec50f520f0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 23 Jun 2011 18:38:51 +0200 Subject: Update 2Geom to pull in integer rectangle class (bzr r10347.1.1) --- src/display/nr-arena-image.cpp | 2 +- src/display/nr-filter-composite.cpp | 1 - src/display/nr-filter-gaussian.cpp | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) (limited to 'src/display') diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp index 36d733eb8..a943a6214 100644 --- a/src/display/nr-arena-image.cpp +++ b/src/display/nr-arena-image.cpp @@ -301,7 +301,7 @@ nr_arena_image_rect (NRArenaImage *image) Geom::Point p(image->ox, image->oy); Geom::Point wh(vw, vh); Geom::Rect view(p, p+wh); - Geom::OptRect res = Geom::intersect(r, view); + Geom::OptRect res = r & view; r = res ? *res : r; } diff --git a/src/display/nr-filter-composite.cpp b/src/display/nr-filter-composite.cpp index d4cf47af4..694ccaec5 100644 --- a/src/display/nr-filter-composite.cpp +++ b/src/display/nr-filter-composite.cpp @@ -11,7 +11,6 @@ #include -#include "2geom/isnan.h" #include "display/cairo-templates.h" #include "display/cairo-utils.h" #include "display/nr-filter-composite.h" diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index 326c37160..884e832ef 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -25,8 +25,6 @@ #include #endif //HAVE_OPENMP -#include "2geom/isnan.h" - #include "display/cairo-utils.h" #include "display/nr-filter-primitive.h" #include "display/nr-filter-gaussian.h" -- cgit v1.2.3 From ab143333746e25648b253f13c0539adff089b1b6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 24 Jun 2011 00:22:07 +0200 Subject: Remove more of libnr (bzr r10347.1.2) --- src/display/canvas-axonomgrid.cpp | 25 ++-- src/display/canvas-grid.cpp | 12 +- src/display/guideline.cpp | 12 +- src/display/nr-arena-glyphs.cpp | 8 +- src/display/nr-arena-group.cpp | 2 +- src/display/nr-arena-item.h | 2 + src/display/nr-arena-shape.cpp | 16 +-- src/display/nr-arena-shape.h | 1 + src/display/nr-arena.cpp | 1 + src/display/nr-filter-displacement-map.cpp | 189 ----------------------------- src/display/nr-filter-turbulence.cpp | 1 - src/display/nr-filter-turbulence.h | 1 - src/display/nr-filter-units.cpp | 17 +-- src/display/nr-filter-units.h | 2 +- src/display/nr-filter.cpp | 8 +- src/display/sp-canvas.cpp | 10 +- src/display/sp-canvas.h | 2 +- 17 files changed, 58 insertions(+), 251 deletions(-) (limited to 'src/display') diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index a9893f09d..daad2d515 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -33,6 +33,7 @@ #include "svg/svg-color.h" #include "util/mathfns.h" #include "xml/node-event-vector.h" +#include "round.h" #define SAFE_SETPIXEL //undefine this when it is certain that setpixel is never called with invalid params @@ -549,13 +550,13 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) // x-axis always goes from topleft to bottomright. (0,0) - (1,1) gdouble const xintercept_y_bc = (buf_tl_gc[Geom::X] * tan_angle[X]) - buf_tl_gc[Geom::Y] ; gdouble const xstart_y_sc = ( xintercept_y_bc - floor(xintercept_y_bc/lyw)*lyw ) + buf->rect.y0; - gint const xlinestart = (gint) Inkscape::round( (xstart_y_sc - buf->rect.x0*tan_angle[X] -ow[Geom::Y]) / lyw ); + gint const xlinestart = round( (xstart_y_sc - buf->rect.x0*tan_angle[X] -ow[Geom::Y]) / lyw ); gint xlinenum = xlinestart; // lines starting on left side. for (y = xstart_y_sc; y < buf->rect.y1; y += lyw, xlinenum++) { gint const x0 = buf->rect.x0; - gint const y0 = (gint) Inkscape::round(y); - gint const x1 = x0 + (gint) Inkscape::round( (buf->rect.y1 - y) / tan_angle[X] ); + gint const y0 = round(y); + gint const x1 = x0 + round( (buf->rect.y1 - y) / tan_angle[X] ); gint const y1 = buf->rect.y1; if (!scaled && (xlinenum % empspacing) != 0) { @@ -570,8 +571,8 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) for (x = xstart_x_sc; x < buf->rect.x1; x += lxw_x, xlinenum--) { gint const y0 = buf->rect.y0; gint const y1 = buf->rect.y1; - gint const x0 = (gint) Inkscape::round(x); - gint const x1 = x0 + (gint) Inkscape::round( (y1 - y0) / tan_angle[X] ); + gint const x0 = round(x); + gint const x1 = x0 + round( (y1 - y0) / tan_angle[X] ); if (!scaled && (xlinenum % empspacing) != 0) { sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color); @@ -582,10 +583,10 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) // y-axis lines (vertical) gdouble const ystart_x_sc = floor (buf_tl_gc[Geom::X] / spacing_ylines) * spacing_ylines + ow[Geom::X]; - gint const ylinestart = (gint) Inkscape::round((ystart_x_sc - ow[Geom::X]) / spacing_ylines); + gint const ylinestart = round((ystart_x_sc - ow[Geom::X]) / spacing_ylines); gint ylinenum = ylinestart; for (x = ystart_x_sc; x < buf->rect.x1; x += spacing_ylines, ylinenum++) { - gint const x0 = (gint) Inkscape::round(x); + gint const x0 = round(x); if (!scaled && (ylinenum % empspacing) != 0) { sp_grid_vline (buf, x0, buf->rect.y0, buf->rect.y1 - 1, color); @@ -597,13 +598,13 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) // z-axis always goes from bottomleft to topright. (0,1) - (1,0) gdouble const zintercept_y_bc = (buf_tl_gc[Geom::X] * -tan_angle[Z]) - buf_tl_gc[Geom::Y] ; gdouble const zstart_y_sc = ( zintercept_y_bc - floor(zintercept_y_bc/lyw)*lyw ) + buf->rect.y0; - gint const zlinestart = (gint) Inkscape::round( (zstart_y_sc + buf->rect.x0*tan_angle[Z] - ow[Geom::Y]) / lyw ); + gint const zlinestart = round( (zstart_y_sc + buf->rect.x0*tan_angle[Z] - ow[Geom::Y]) / lyw ); gint zlinenum = zlinestart; // lines starting from left side for (y = zstart_y_sc; y < buf->rect.y1; y += lyw, zlinenum++) { gint const x0 = buf->rect.x0; - gint const y0 = (gint) Inkscape::round(y); - gint const x1 = x0 + (gint) Inkscape::round( (y - buf->rect.y0 ) / tan_angle[Z] ); + gint const y0 = round(y); + gint const x1 = x0 + round( (y - buf->rect.y0 ) / tan_angle[Z] ); gint const y1 = buf->rect.y0; if (!scaled && (zlinenum % empspacing) != 0) { @@ -617,8 +618,8 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) for (x = zstart_x_sc; x < buf->rect.x1; x += lxw_z, zlinenum++) { gint const y0 = buf->rect.y1; gint const y1 = buf->rect.y0; - gint const x0 = (gint) Inkscape::round(x); - gint const x1 = x0 + (gint) Inkscape::round( (buf->rect.y1 - buf->rect.y0) / tan_angle[Z] ); + gint const x0 = round(x); + gint const x1 = x0 + round( (buf->rect.y1 - buf->rect.y0) / tan_angle[Z] ); if (!scaled && (zlinenum % empspacing) != 0) { sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color); diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 82ea036f6..52963ce6b 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -918,9 +918,9 @@ void CanvasXYGrid::Render (SPCanvasBuf *buf) { gdouble const sxg = floor ((buf->rect.x0 - ow[Geom::X]) / sw[Geom::X]) * sw[Geom::X] + ow[Geom::X]; - gint const xlinestart = (gint) Inkscape::round((sxg - ow[Geom::X]) / sw[Geom::X]); + gint const xlinestart = round((sxg - ow[Geom::X]) / sw[Geom::X]); gdouble const syg = floor ((buf->rect.y0 - ow[Geom::Y]) / sw[Geom::Y]) * sw[Geom::Y] + ow[Geom::Y]; - gint const ylinestart = (gint) Inkscape::round((syg - ow[Geom::Y]) / sw[Geom::Y]); + gint const ylinestart = round((syg - ow[Geom::Y]) / sw[Geom::Y]); //set correct coloring, depending preference (when zoomed out, always major coloring or minor coloring) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -941,7 +941,7 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) gint ylinenum; gdouble y; for (y = syg, ylinenum = ylinestart; y < buf->rect.y1; y += sw[Geom::Y], ylinenum++) { - gint const y0 = (gint) Inkscape::round(y); + gint const y0 = round(y); if (!scaled[Geom::Y] && (ylinenum % empspacing) != 0) { grid_hline (buf, y0, buf->rect.x0, buf->rect.x1 - 1, color); } else { @@ -952,7 +952,7 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) gint xlinenum; gdouble x; for (x = sxg, xlinenum = xlinestart; x < buf->rect.x1; x += sw[Geom::X], xlinenum++) { - gint const ix = (gint) Inkscape::round(x); + gint const ix = round(x); if (!scaled[Geom::X] && (xlinenum % empspacing) != 0) { grid_vline (buf, ix, buf->rect.y0, buf->rect.y1, color); } else { @@ -963,12 +963,12 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) gint ylinenum; gdouble y; for (y = syg, ylinenum = ylinestart; y < buf->rect.y1; y += sw[Geom::Y], ylinenum++) { - gint const iy = (gint) Inkscape::round(y); + gint const iy = round(y); gint xlinenum; gdouble x; for (x = sxg, xlinenum = xlinestart; x < buf->rect.x1; x += sw[Geom::X], xlinenum++) { - gint const ix = (gint) Inkscape::round(x); + gint const ix = round(x); if ( (!scaled[Geom::X] && (xlinenum % empspacing) != 0) || (!scaled[Geom::Y] && (ylinenum % empspacing) != 0) || ((scaled[Geom::X] || scaled[Geom::Y]) && no_emp_when_zoomed_out) ) diff --git a/src/display/guideline.cpp b/src/display/guideline.cpp index c761fa74e..c1c3e7740 100644 --- a/src/display/guideline.cpp +++ b/src/display/guideline.cpp @@ -112,8 +112,8 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf) cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE); cairo_set_font_size(buf->ct, 10); - int px = (int) Inkscape::round(gl->point_on_line[Geom::X]); - int py = (int) Inkscape::round(gl->point_on_line[Geom::Y]); + int px = round(gl->point_on_line[Geom::X]); + int py = round(gl->point_on_line[Geom::Y]); if (gl->label) { cairo_save(buf->ct); @@ -126,12 +126,12 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf) } if (gl->is_vertical()) { - int position = (int) Inkscape::round(gl->point_on_line[Geom::X]); + int position = round(gl->point_on_line[Geom::X]); cairo_move_to(buf->ct, position + 0.5, buf->rect.y0 + 0.5); cairo_line_to(buf->ct, position + 0.5, buf->rect.y1 - 0.5); cairo_stroke(buf->ct); } else if (gl->is_horizontal()) { - int position = (int) Inkscape::round(gl->point_on_line[Geom::Y]); + int position = round(gl->point_on_line[Geom::Y]); cairo_move_to(buf->ct, buf->rect.x0 + 0.5, position + 0.5); cairo_line_to(buf->ct, buf->rect.x1 - 0.5, position + 0.5); cairo_stroke(buf->ct); @@ -193,9 +193,9 @@ static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine, sp_canvas_item_request_update(SP_CANVAS_ITEM (gl->origin)); if (gl->is_horizontal()) { - sp_canvas_update_bbox (item, -1000000, (int) Inkscape::round(gl->point_on_line[Geom::Y] - 16), 1000000, (int) Inkscape::round(gl->point_on_line[Geom::Y] + 1)); + sp_canvas_update_bbox (item, -1000000, round(gl->point_on_line[Geom::Y] - 16), 1000000, round(gl->point_on_line[Geom::Y] + 1)); } else if (gl->is_vertical()) { - sp_canvas_update_bbox (item, (int) Inkscape::round(gl->point_on_line[Geom::X]), -1000000, (int) Inkscape::round(gl->point_on_line[Geom::X] + 16), 1000000); + sp_canvas_update_bbox (item, round(gl->point_on_line[Geom::X]), -1000000, round(gl->point_on_line[Geom::X] + 16), 1000000); } else { //TODO: labels in angled guidelines are not showing up for some reason. sp_canvas_update_bbox (item, -1000000, -1000000, 1000000, 1000000); diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index dbac07596..0e20f0ddb 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -135,10 +135,10 @@ nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*s } if (b) { - item->bbox.x0 = static_cast(floor(b->left())); - item->bbox.y0 = static_cast(floor(b->top())); - item->bbox.x1 = static_cast(ceil (b->right())); - item->bbox.y1 = static_cast(ceil (b->bottom())); + item->bbox.x0 = floor(b->left()); + item->bbox.y0 = floor(b->top()); + item->bbox.x1 = ceil (b->right()); + item->bbox.y1 = ceil (b->bottom()); } else { item->bbox.x0 = 0; item->bbox.y0 = 0; diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 97f92d02d..d1e6869aa 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -176,7 +176,7 @@ nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int } if (beststate & NR_ARENA_ITEM_STATE_BBOX) { - nr_rect_l_set_empty (&item->bbox); + item->bbox = NR_RECT_L_EMPTY; for (NRArenaItem *child = group->children; child != NULL; child = child->next) { if (child->visible) nr_rect_l_union (&item->bbox, &item->bbox, &child->drawbox); diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h index 0fc4cbe48..d65a75ed8 100644 --- a/src/display/nr-arena-item.h +++ b/src/display/nr-arena-item.h @@ -15,6 +15,8 @@ #include #include <2geom/affine.h> +#include <2geom/rect.h> +#include "libnr/nr-forward.h" #include "libnr/nr-rect-l.h" #include "libnr/nr-object.h" #include "gc-soft-ptr.h" diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index eb7a30e58..ff87b5134 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -223,10 +223,10 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g if (shape->curve) { boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); if (boundingbox) { - item->bbox.x0 = static_cast(floor((*boundingbox)[0][0])); // Floor gives the coordinate in which the point resides - item->bbox.y0 = static_cast(floor((*boundingbox)[1][0])); - item->bbox.x1 = static_cast(ceil ((*boundingbox)[0][1])); // Ceil gives the first coordinate beyond the point - item->bbox.y1 = static_cast(ceil ((*boundingbox)[1][1])); + item->bbox.x0 = floor((*boundingbox)[0][0]); // Floor gives the coordinate in which the point resides + item->bbox.y0 = floor((*boundingbox)[1][0]); + item->bbox.x1 = ceil ((*boundingbox)[0][1]); // Ceil gives the first coordinate beyond the point + item->bbox.y1 = ceil ((*boundingbox)[1][1]); } else { item->bbox = NR_RECT_L_EMPTY; } @@ -274,10 +274,10 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g /// \todo just write item->bbox = boundingbox if (boundingbox) { - shape->approx_bbox.x0 = static_cast(floor((*boundingbox)[0][0])); - shape->approx_bbox.y0 = static_cast(floor((*boundingbox)[1][0])); - shape->approx_bbox.x1 = static_cast(ceil ((*boundingbox)[0][1])); - shape->approx_bbox.y1 = static_cast(ceil ((*boundingbox)[1][1])); + shape->approx_bbox.x0 = floor(boundingbox->left()); + shape->approx_bbox.y0 = floor(boundingbox->top()); + shape->approx_bbox.x1 = ceil (boundingbox->right()); + shape->approx_bbox.y1 = ceil (boundingbox->bottom()); } else { shape->approx_bbox = NR_RECT_L_EMPTY; } diff --git a/src/display/nr-arena-shape.h b/src/display/nr-arena-shape.h index 2ee0d24c8..7b86f7f59 100644 --- a/src/display/nr-arena-shape.h +++ b/src/display/nr-arena-shape.h @@ -22,6 +22,7 @@ #include "forward.h" #include "nr-arena-item.h" #include "nr-style.h" +#include "libnr/nr-rect.h" NRType nr_arena_shape_get_type (void); diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp index 43edb6918..ce62a81dc 100644 --- a/src/display/nr-arena.cpp +++ b/src/display/nr-arena.cpp @@ -18,6 +18,7 @@ #include "nr-filter-types.h" #include "preferences.h" #include "color.h" +#include "libnr/nr-rect.h" static void nr_arena_class_init (NRArenaClass *klass); static void nr_arena_init (NRArena *arena); diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp index fdaf2c887..15200223b 100644 --- a/src/display/nr-filter-displacement-map.cpp +++ b/src/display/nr-filter-displacement-map.cpp @@ -28,128 +28,6 @@ FilterPrimitive * FilterDisplacementMap::create() { FilterDisplacementMap::~FilterDisplacementMap() {} -#if 0 -struct pixel_t { - unsigned char channels[4]; - inline unsigned char operator[](int c) const { return channels[c]; } - inline unsigned char& operator[](int c) { return channels[c]; } - static inline pixel_t blank() { - pixel_t p; - for(unsigned int i=0; i<4; i++) { - p[i] = 0; - } - return p; - } -}; - -static inline pixel_t pixelValue(NRPixBlock const* pb, int x, int y) { - if ( x < pb->area.x0 || x >= pb->area.x1 || y < pb->area.y0 || y >= pb->area.y1 ) return pixel_t::blank(); // This assumes anything outside the defined range is (0,0,0,0) - pixel_t const* rowData = reinterpret_cast(NR_PIXBLOCK_PX(pb) + (y-pb->area.y0)*pb->rs); - return rowData[x-pb->area.x0]; -} - -template -static pixel_t interpolatePixels(NRPixBlock const* pb, double x, double y) { - // NOTE: The values of x and y are shifted by -0.5 (the "true" values would be x+0.5 and y+0.5). - // This is done because otherwise the pixel values first have to be shifted by +0.5 and then by -0.5 again... - unsigned int const sfl = 8u; - unsigned int const sf = 1u<(round(sf * (x - xi))), - yf = static_cast(round(sf * (y - yi))); - pixel_t p00 = pixelValue(pb, xi+0, yi+0); - pixel_t p01 = pixelValue(pb, xi+1, yi+0); - pixel_t p10 = pixelValue(pb, xi+0, yi+1); - pixel_t p11 = pixelValue(pb, xi+1, yi+1); - - /* It's a good idea to interpolate premultiplied colors: - * - * Consider two pixels, one being rgba(255,0,0,0), which is fully transparent, - * and the other being rgba(0,0,255,255), or blue (fully opaque). - * If these two colors are interpolated the expected result would be bluish pixels - * containing no red. - * - * However, if our final alpha value is zero, then the RGB values aren't really determinate. - * We might as well avoid premultiplication in this case, which still gives us a fully - * transparent result, but with interpolated RGB parts. */ - - pixel_t r; - if (PREMULTIPLIED) { - /* Premultiplied, so do simple interpolation. */ - for (unsigned i = 0; i != 4; ++i) { - // y0,y1 have range [0,a*sf] - unsigned const y0 = sf*p00[i] + xf*((unsigned int)p01[i]-(unsigned int)p00[i]); - unsigned const y1 = sf*p10[i] + xf*((unsigned int)p11[i]-(unsigned int)p10[i]); - - unsigned const ri = sf*y0 + yf*(y1-y0); // range [0,a*sf*sf] - r[i] = (ri + sf2h)>>(2*sfl); // range [0,a] - } - } else { - /* First calculate interpolated alpha value. */ - unsigned const y0 = sf*p00[3] + xf*((unsigned int)p01[3]-(unsigned int)p00[3]); // range [0,a*sf] - unsigned const y1 = sf*p10[3] + xf*((unsigned int)p11[3]-(unsigned int)p10[3]); - unsigned const ra = sf*y0 + yf*(y1-y0); // range [0,a*sf*sf] - - if (ra==0) { - /* Fully transparent, so do simple interpolation. */ - for (unsigned i = 0; i != 3; ++i) { - // y0,y1 have range [0,255*sf] - unsigned const y0 = sf*p00[i] + xf*((unsigned int)p01[i]-(unsigned int)p00[i]); - unsigned const y1 = sf*p10[i] + xf*((unsigned int)p11[i]-(unsigned int)p10[i]); - - unsigned const ri = sf*y0 + yf*(y1-y0); // range [0,255*sf*sf] - r[i] = (ri + sf2h)>>(2*sfl); // range [0,255] - } - r[3] = 0; - } else { - /* Do premultiplication ourselves. */ - for (unsigned i = 0; i != 3; ++i) { - // Premultiplied versions. Range [0,255*a]. - unsigned const c00 = p00[i]*p00[3]; - unsigned const c01 = p01[i]*p01[3]; - unsigned const c10 = p10[i]*p10[3]; - unsigned const c11 = p11[i]*p11[3]; - - // Interpolation. - unsigned const y0 = sf*c00 + xf*(c01-c00); // range [0,255*a*sf] - unsigned const y1 = sf*c10 + xf*(c11-c10); // range [0,255*a*sf] - unsigned const ri = sf*y0 + yf*(y1-y0); // range [0,255*a*sf*sf] - r[i] = (ri + ra/2) / ra; // range [0,255] - } - r[3] = (ra + sf2h)>>(2*sfl); // range [0,a] - } - } - - return r; -} - -template -static void performDisplacement(NRPixBlock const* texture, NRPixBlock const* map, int Xchannel, int Ychannel, NRPixBlock* out, double scalex, double scaley) { - bool Xneedsdemul = MAP_PREMULTIPLIED && Xchannel<3; - bool Yneedsdemul = MAP_PREMULTIPLIED && Ychannel<3; - if (!Xneedsdemul) scalex /= 255.0; - if (!Yneedsdemul) scaley /= 255.0; - - for (int yout=out->area.y0; yout < out->area.y1; yout++){ - pixel_t const* mapRowData = reinterpret_cast(NR_PIXBLOCK_PX(map) + (yout-map->area.y0)*map->rs); - pixel_t* outRowData = reinterpret_cast(NR_PIXBLOCK_PX(out) + (yout-out->area.y0)*out->rs); - for (int xout=out->area.x0; xout < out->area.x1; xout++){ - pixel_t const mapValue = mapRowData[xout-map->area.x0]; - - double xtex = xout + (Xneedsdemul ? // Although the value of the pixel corresponds to the MIDDLE of the pixel, no +0.5 is needed because we're interpolating pixels anyway (so to get the actual pixel locations 0.5 would have to be subtracted again). - (mapValue[3]==0?0:(scalex * (mapValue[Xchannel] - mapValue[3]*0.5) / mapValue[3])) : - (scalex * (mapValue[Xchannel] - 127.5))); - double ytex = yout + (Yneedsdemul ? - (mapValue[3]==0?0:(scaley * (mapValue[Ychannel] - mapValue[3]*0.5) / mapValue[3])) : - (scaley * (mapValue[Ychannel] - 127.5))); - - outRowData[xout-out->area.x0] = interpolatePixels(texture, xtex, ytex); - } - } -} -#endif - struct Displace { Displace(cairo_surface_t *texture, cairo_surface_t *map, unsigned xch, unsigned ych, double scalex, double scaley) @@ -206,73 +84,6 @@ void FilterDisplacementMap::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -/* -int FilterDisplacementMap::render(FilterSlot &slot, FilterUnits const &units) { - NRPixBlock *texture = slot.get(_input); - NRPixBlock *map = slot.get(_input2); - - // Bail out if either one of source images is missing - if (!map || !texture) { - g_warning("Missing source image for feDisplacementMap (map=%d texture=%d)", _input, _input2); - return 1; - } - - NR::IRect area = units.get_pixblock_filterarea_paraller(); - int x0 = std::max(map->area.x0,area.min()[NR::X]); - int y0 = std::max(map->area.y0,area.min()[NR::Y]); - int x1 = std::min(map->area.x1,area.max()[NR::X]); - int y1 = std::min(map->area.y1,area.max()[NR::Y]); - - //TODO: check whether we really need this check: - if (x1 <= x0 || y1 <= y0) return 0; //nothing to do! - - if (texture->mode != NR_PIXBLOCK_MODE_R8G8B8A8N && texture->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - g_warning("Source images without an alpha channel are not supported by feDisplacementMap at the moment."); - return 1; - } - - NRPixBlock *out = new NRPixBlock; - nr_pixblock_setup_fast(out, texture->mode, x0, y0, x1, y1, true); - - // convert to a suitable format - bool free_map_on_exit = false; - if (map->mode != NR_PIXBLOCK_MODE_R8G8B8A8N && map->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - NRPixBlock *original_map = map; - map = new NRPixBlock; - nr_pixblock_setup_fast(map, NR_PIXBLOCK_MODE_R8G8B8A8N, - original_map->area.x0, original_map->area.y0, - original_map->area.x1, original_map->area.y1, - false); - nr_blit_pixblock_pixblock(map, original_map); - free_map_on_exit = true; - } - bool map_premultiplied = (map->mode == NR_PIXBLOCK_MODE_R8G8B8A8P); - bool data_premultiplied = (out->mode == NR_PIXBLOCK_MODE_R8G8B8A8P); - - Geom::Affine trans = units.get_matrix_primitiveunits2pb(); - double scalex = scale * trans.expansionX(); - double scaley = scale * trans.expansionY(); - - if (map_premultiplied && data_premultiplied) { - performDisplacement(texture, map, Xchannel, Ychannel, out, scalex, scaley); - } else if (map_premultiplied && !data_premultiplied) { - performDisplacement(texture, map, Xchannel, Ychannel, out, scalex, scaley); - } else if (data_premultiplied) { - performDisplacement(texture, map, Xchannel, Ychannel, out, scalex, scaley); - } else { - performDisplacement(texture, map, Xchannel, Ychannel, out, scalex, scaley); - } - - if (free_map_on_exit) { - nr_pixblock_release(map); - delete map; - } - - out->empty = FALSE; - slot.set(_output, out); - return 0; -}*/ - void FilterDisplacementMap::set_input(int slot) { _input = slot; } diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp index f3b03c024..60d5ce872 100644 --- a/src/display/nr-filter-turbulence.cpp +++ b/src/display/nr-filter-turbulence.cpp @@ -299,7 +299,6 @@ FilterTurbulence::FilterTurbulence() , numOctaves(1) , seed(0) , updated(false) - , updated_area(NR::IPoint(), NR::IPoint()) , fTileWidth(10) //guessed , fTileHeight(10) //guessed , fTileX(1) //guessed diff --git a/src/display/nr-filter-turbulence.h b/src/display/nr-filter-turbulence.h index 50161b6be..8d3639543 100644 --- a/src/display/nr-filter-turbulence.h +++ b/src/display/nr-filter-turbulence.h @@ -64,7 +64,6 @@ private: bool stitchTiles; FilterTurbulenceType type; bool updated; - NR::IRect updated_area; unsigned char *pix_data; double fTileWidth; diff --git a/src/display/nr-filter-units.cpp b/src/display/nr-filter-units.cpp index b1c475c41..a8686545a 100644 --- a/src/display/nr-filter-units.cpp +++ b/src/display/nr-filter-units.cpp @@ -158,22 +158,13 @@ Geom::Affine FilterUnits::get_matrix_user2primitiveunits() const { return get_matrix_user2units(primitiveUnits); } -NR::IRect FilterUnits::get_pixblock_filterarea_paraller() const { +Geom::IntRect FilterUnits::get_pixblock_filterarea_paraller() const { g_assert(filter_area); - int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN; Geom::Affine u2pb = get_matrix_user2pb(); - - for (int i = 0 ; i < 4 ; i++) { - Geom::Point p = filter_area->corner(i); - p *= u2pb; - if (p[X] < min_x) min_x = (int)std::floor(p[X]); - if (p[X] > max_x) max_x = (int)std::ceil(p[X]); - if (p[Y] < min_y) min_y = (int)std::floor(p[Y]); - if (p[Y] > max_y) max_y = (int)std::ceil(p[Y]); - } - NR::IRect ret(NR::IPoint(min_x, min_y), NR::IPoint(max_x, max_y)); - return ret; + Geom::Rect r = *filter_area * u2pb; + Geom::IntRect ir = r.roundOutwards(); + return ir; } FilterUnits& FilterUnits::operator=(FilterUnits const &other) { diff --git a/src/display/nr-filter-units.h b/src/display/nr-filter-units.h index 2fc3e5533..1cb4fdbce 100644 --- a/src/display/nr-filter-units.h +++ b/src/display/nr-filter-units.h @@ -133,7 +133,7 @@ public: * NOTE: use only in filters, that define TRAIT_PARALLER in * get_input_traits. The filter effects area may not be representable * by simple rectangle otherwise. */ - NR::IRect get_pixblock_filterarea_paraller() const; + Geom::IntRect get_pixblock_filterarea_paraller() const; FilterUnits& operator=(FilterUnits const &other); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 55190b00c..a0997cc1b 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -238,10 +238,10 @@ void Filter::compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox) { Geom::Rect enlarged = filter_effect_area(tmp_bbox); enlarged = enlarged * item->ctm; - item_bbox.x0 = (NR::ICoord) floor(enlarged.min()[X]); - item_bbox.y0 = (NR::ICoord) floor(enlarged.min()[Y]); - item_bbox.x1 = (NR::ICoord) ceil(enlarged.max()[X]); - item_bbox.y1 = (NR::ICoord) ceil(enlarged.max()[Y]); + item_bbox.x0 = floor(enlarged.min()[X]); + item_bbox.y0 = floor(enlarged.min()[Y]); + item_bbox.x1 = ceil(enlarged.max()[X]); + item_bbox.y1 = ceil(enlarged.max()[Y]); } Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 472c9ada5..977452834 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -2306,13 +2306,15 @@ Geom::Rect SPCanvas::getViewbox() const } /** - * Return canvas window coordinates as IRect (a rectangle defined by integers). + * Return canvas window coordinates as integer rectangle. */ -NR::IRect SPCanvas::getViewboxIntegers() const +Geom::IntRect SPCanvas::getViewboxIntegers() const { GtkWidget const *w = GTK_WIDGET(this); - return NR::IRect(NR::IPoint(x0, y0), - NR::IPoint(x0 + w->allocation.width, y0 + w->allocation.height)); + Geom::IntRect ret; + ret.setMin(Geom::IntPoint(x0, y0)); + ret.setMax(Geom::IntPoint(x0 + w->allocation.width, y0 + w->allocation.height)); + return ret; } inline int sp_canvas_tile_floor(int x) diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 7a6b3295e..32747e7c5 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -149,7 +149,7 @@ struct SPCanvas { bool is_scrolling; Geom::Rect getViewbox() const; - NR::IRect getViewboxIntegers() const; + Geom::IntRect getViewboxIntegers() const; }; GtkWidget *sp_canvas_new_aa(); -- cgit v1.2.3 From a3e406b2ceafb8fb6b44db0a7816a083d7b3c8ee Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 9 Jul 2011 02:52:06 +0200 Subject: Add SPCanvasArena caching layer. Currently breaks for clipped groups that contain filtered objects (Cairo clipping bug?) (bzr r10347.1.6) --- src/display/canvas-arena.cpp | 154 ++++++++++++++++++++++++++++++++++++------ src/display/canvas-arena.h | 4 ++ src/display/nr-arena-item.cpp | 4 +- src/display/sp-canvas-item.h | 4 +- src/display/sp-canvas.cpp | 30 +++++++- 5 files changed, 173 insertions(+), 23 deletions(-) (limited to 'src/display') diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index 6930e4d7c..dd4a4ed5c 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -31,7 +31,10 @@ static void sp_canvas_arena_destroy(GtkObject *object); static void sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf); +static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect const &area); +static void sp_canvas_arena_dirty_cache (SPCanvasArena *arena, NRRectL *area); static double sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); +static void sp_canvas_arena_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area); static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event); static gint sp_canvas_arena_send_event (SPCanvasArena *arena, GdkEvent *event); @@ -93,6 +96,7 @@ sp_canvas_arena_class_init (SPCanvasArenaClass *klass) item_class->render = sp_canvas_arena_render; item_class->point = sp_canvas_arena_point; item_class->event = sp_canvas_arena_event; + item_class->visible_area_changed = sp_canvas_arena_visible_area_changed; } static void @@ -106,6 +110,9 @@ sp_canvas_arena_init (SPCanvasArena *arena) nr_arena_group_set_transparent (NR_ARENA_GROUP (arena->root), TRUE); arena->active = NULL; + arena->cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + arena->cache_area = Geom::IntRect::from_xywh(0,0,1,1); + arena->dirty = cairo_region_create(); nr_active_object_add_listener ((NRActiveObject *) arena->arena, (NRObjectEventVector *) &carenaev, sizeof (carenaev), arena); } @@ -131,6 +138,11 @@ sp_canvas_arena_destroy (GtkObject *object) nr_object_unref ((NRObject *) arena->arena); arena->arena = NULL; } + if (arena->cache) { + cairo_surface_destroy(arena->cache); + arena->cache = NULL; + } + cairo_region_destroy(arena->dirty); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -187,33 +199,74 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) { - gint bw, bh; - SPCanvasArena *arena = SP_CANVAS_ARENA (item); //SPCanvas *canvas = item->canvas; - 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); + //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); + + Geom::OptIntRect r = buf->rect; + if (!r || r->hasZeroArea()) return; + + cairo_rectangle_int_t crect; + crect.x = r->left(); + crect.y = r->top(); + crect.width = r->width(); + crect.height = r->height(); + if (cairo_region_contains_rectangle(arena->dirty, &crect) != CAIRO_REGION_OVERLAP_OUT) { + sp_canvas_arena_render_cache(item, *r); + cairo_region_subtract_rectangle(arena->dirty, &crect); + } - sp_canvas_prepare_buffer(buf); + cairo_save(buf->ct); + cairo_translate(buf->ct, -r->left(), -r->top()); + //cairo_rectangle(buf->ct, r->left(), r->top(), r->width(), r->height()); + //cairo_clip(buf->ct); + cairo_set_source_surface(buf->ct, arena->cache, arena->cache_area.left(), arena->cache_area.top()); + cairo_paint(buf->ct); + //nr_arena_item_invoke_render (buf->ct, arena->root, &area, NULL, 0); + cairo_restore(buf->ct); +} - bw = buf->rect.x1 - buf->rect.x0; - bh = buf->rect.y1 - buf->rect.y0; - if ((bw < 1) || (bh < 1)) return; +static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect const &area) +{ + SPCanvasArena *arena = SP_CANVAS_ARENA (item); + + Geom::OptIntRect r = Geom::intersect(arena->cache_area, area); + if (!r || r->hasZeroArea()) return; // nothing to do + + cairo_t *ct = cairo_create(arena->cache); + cairo_translate(ct, -arena->cache_area.left(), -arena->cache_area.top()); + + // clear area to paint + cairo_rectangle(ct, area.left(), area.top(), area.width(), area.height()); + cairo_clip(ct); + cairo_save(ct); + cairo_set_source_rgba(ct, 0,0,0,0); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_restore(ct); + + NRRectL nr_area(r); - NRRectL area; + 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); + nr_arena_item_invoke_render (ct, arena->root, &nr_area, NULL, 0); - area.x0 = buf->rect.x0; - area.y0 = buf->rect.y0; - area.x1 = buf->rect.x1; - area.y1 = buf->rect.y1; + cairo_destroy(ct); +} - sp_canvas_prepare_buffer(buf); - cairo_save(buf->ct); - cairo_translate(buf->ct, -area.x0, -area.y0); - nr_arena_item_invoke_render (buf->ct, arena->root, &area, NULL, 0); - cairo_restore(buf->ct); +static void +sp_canvas_arena_dirty_cache (SPCanvasArena *arena, NRRectL *area) +{ + cairo_rectangle_int_t rect; + rect.x = area->x0; + rect.y = area->y0; + rect.width = area->x1 - area->x0; + rect.height = area->y1 - area->y0; + cairo_region_union_rectangle(arena->dirty, &rect); } static double @@ -237,6 +290,67 @@ sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_ return 1e18; } +static void +sp_canvas_arena_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area) +{ + SPCanvasArena *arena = SP_CANVAS_ARENA(item); + + cairo_surface_t *new_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + new_area.width(), new_area.height()); + cairo_t *ct = cairo_create(new_cache); + cairo_set_source_surface(ct, arena->cache, old_area.left() - new_area.left(), old_area.top() - new_area.top()); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_destroy(ct); + cairo_surface_destroy(arena->cache); + arena->cache = new_cache; + arena->cache_area = new_area; + + cairo_rectangle_int_t crect; + crect.x = new_area.left(); + crect.y = new_area.top(); + crect.width = new_area.width(); + crect.height = new_area.height(); + cairo_region_intersect_rectangle(arena->dirty, &crect); + + // invalidate newly exposed areas + /* + * +----------------------+ + * | top strip | + * +-------+------+-------+ + * | | | | + * | left | old | right | + * | strip | area | strip | + * | | | | + * +-------+------+-------+ + * | bottom strip | + * +----------------------+ + */ + + // top strip + if (new_area.top() < old_area.top()) { + NRRectL top_strip(new_area.left(), new_area.top(), new_area.right(), old_area.top()); + sp_canvas_arena_dirty_cache(arena, &top_strip); + } + // left strip + if (new_area.left() < old_area.left()) { + NRRectL left_strip(new_area.left(), std::max(new_area.top(), old_area.top()), + old_area.left(), std::min(new_area.bottom(), old_area.bottom())); + sp_canvas_arena_dirty_cache(arena, &left_strip); + } + // right strip + if (new_area.right() > old_area.right()) { + NRRectL right_strip(old_area.right(), std::max(new_area.top(), old_area.top()), + new_area.right(), std::min(new_area.bottom(), old_area.bottom())); + sp_canvas_arena_dirty_cache(arena, &right_strip); + } + // bottom strip + if (new_area.bottom() > old_area.bottom()) { + NRRectL bottom_strip(new_area.left(), old_area.bottom(), new_area.right(), new_area.bottom()); + sp_canvas_arena_dirty_cache(arena, &bottom_strip); + } +} + static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) { @@ -336,6 +450,8 @@ sp_canvas_arena_request_update (NRArena */*arena*/, NRArenaItem */*item*/, void static void sp_canvas_arena_request_render (NRArena */*arena*/, NRRectL *area, void *data) { + if (!area) return; + sp_canvas_arena_dirty_cache (SP_CANVAS_ARENA(data), area); sp_canvas_request_redraw (SP_CANVAS_ITEM (data)->canvas, area->x0, area->y0, area->x1, area->y1); } diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h index 4cfeccb5a..220976da0 100644 --- a/src/display/canvas-arena.h +++ b/src/display/canvas-arena.h @@ -45,6 +45,10 @@ struct _SPCanvasArena { /* fixme: */ NRArenaItem *picked; gdouble delta; + + Geom::IntRect cache_area; + cairo_surface_t *cache; + cairo_region_t *dirty; }; struct _SPCanvasArenaClass { diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 526882921..9c7af1077 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -21,6 +21,7 @@ #include "display/cairo-utils.h" #include "display/cairo-templates.h" +#include "display/canvas-arena.h" #include "nr-arena.h" #include "nr-arena-item.h" #include "gc-core.h" @@ -482,7 +483,8 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area // apply filter if (item->filter && filter) { - item->filter->render(item, ct, area, this_ct, &carea); + NRRectL bgarea(item->arena->canvasarena->cache_area); + item->filter->render(item, ct, &bgarea, this_ct, &carea); } if (needs_intermediate_rendering) { diff --git a/src/display/sp-canvas-item.h b/src/display/sp-canvas-item.h index 9dbec547e..4c731e56b 100644 --- a/src/display/sp-canvas-item.h +++ b/src/display/sp-canvas-item.h @@ -24,8 +24,7 @@ #include #include #include - -#include "2geom/rect.h" +#include <2geom/rect.h> G_BEGIN_DECLS @@ -65,6 +64,7 @@ struct _SPCanvasItemClass : public GtkObjectClass { double (* point) (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); int (* event) (SPCanvasItem *item, GdkEvent *event); + void (* visible_area_changed) (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area); }; SPCanvasItem *sp_canvas_item_new(SPCanvasGroup *parent, GType type, const gchar *first_arg_name, ...); diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 23c6a430e..29729ef6c 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -691,6 +691,7 @@ static void sp_canvas_group_destroy (GtkObject *object); static void sp_canvas_group_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static double sp_canvas_group_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); static void sp_canvas_group_render (SPCanvasItem *item, SPCanvasBuf *buf); +static void sp_canvas_group_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area); static SPCanvasItemClass *group_parent_class; @@ -734,6 +735,7 @@ sp_canvas_group_class_init (SPCanvasGroupClass *klass) item_class->update = sp_canvas_group_update; item_class->render = sp_canvas_group_render; item_class->point = sp_canvas_group_point; + item_class->visible_area_changed = sp_canvas_group_visible_area_changed; } /** @@ -877,6 +879,20 @@ sp_canvas_group_render (SPCanvasItem *item, SPCanvasBuf *buf) } } +static void +sp_canvas_group_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area) +{ + SPCanvasGroup *group = SP_CANVAS_GROUP (item); + + for (GList *list = group->items; list; list = list->next) { + SPCanvasItem *child = (SPCanvasItem *)list->data; + if (child->flags & SP_CANVAS_ITEM_VISIBLE) { + if (SP_CANVAS_ITEM_GET_CLASS (child)->visible_area_changed) + SP_CANVAS_ITEM_GET_CLASS (child)->visible_area_changed (child, old_area, new_area); + } + } +} + /** * Adds an item to a canvas group. */ @@ -1218,8 +1234,16 @@ sp_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { SPCanvas *canvas = SP_CANVAS (widget); + Geom::IntRect old_area = Geom::IntRect::from_xywh(canvas->x0, canvas->y0, + widget->allocation.width, widget->allocation.height); + Geom::IntRect new_area = Geom::IntRect::from_xywh(canvas->x0, canvas->y0, + allocation->width, allocation->height); + /* Schedule redraw of new region */ sp_canvas_resize_tiles(canvas,canvas->x0,canvas->y0,canvas->x0+allocation->width,canvas->y0+allocation->height); + if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed) + SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed (canvas->root, old_area, new_area); + if (allocation->width > widget->allocation.width) { sp_canvas_request_redraw (canvas, canvas->x0 + widget->allocation.width, @@ -2152,12 +2176,17 @@ sp_canvas_scroll_to (SPCanvas *canvas, double cx, double cy, unsigned int clear, int dx = ix - canvas->x0; // dx and dy specify the displacement (scroll) of the int dy = iy - canvas->y0; // canvas w.r.t its previous position + Geom::IntRect old_area = canvas->getViewboxIntegers(); + Geom::IntRect new_area = old_area + Geom::IntPoint(dx, dy); + canvas->dx0 = cx; // here the 'd' stands for double, not delta! canvas->dy0 = cy; canvas->x0 = ix; canvas->y0 = iy; sp_canvas_resize_tiles (canvas, canvas->x0, canvas->y0, canvas->x0+canvas->widget.allocation.width, canvas->y0+canvas->widget.allocation.height); + if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed) + SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed (canvas->root, old_area, new_area); if (!clear) { // scrolling without zoom; redraw only the newly exposed areas @@ -2170,7 +2199,6 @@ sp_canvas_scroll_to (SPCanvas *canvas, double cx, double cy, unsigned int clear, } else { // scrolling as part of zoom; do nothing here - the next do_update will perform full redraw } - } /** -- cgit v1.2.3 From f8a34926de0258e7b82ec5336aa394834f42b55b Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 10 Jul 2011 01:03:55 +0200 Subject: Redesign the rendering pipeline. Clipping paths are now rasterized. This fixes breakage related to clipped groups and correctly handles nested clipping paths. Also add the ability to use text objects as clipping paths. (bzr r10347.1.7) --- src/display/nr-arena-glyphs.cpp | 31 +++--- src/display/nr-arena-group.cpp | 1 - src/display/nr-arena-item.cpp | 206 ++++++++++++++++++++++++---------------- src/display/nr-arena-shape.cpp | 25 +++-- 4 files changed, 154 insertions(+), 109 deletions(-) (limited to 'src/display') diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index 0e20f0ddb..185551d31 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -282,7 +282,8 @@ nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint s } -static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock * /*pb*/, unsigned int /*flags*/) +static unsigned int +nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock * /*pb*/, unsigned int /*flags*/) { NRArenaItem *child = 0; @@ -309,9 +310,11 @@ static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, Geom::Affine transform = g->g_transform * group->ctm; cairo_new_path(ct); + cairo_save(ct); ink_cairo_transform(ct, transform); feed_pathvector_to_cairo (ct, *pathv); cairo_fill(ct); + cairo_restore(ct); } return item->state; @@ -352,20 +355,26 @@ static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, return item->state; } -static unsigned int nr_arena_glyphs_group_clip(cairo_t * /*ct*/, NRArenaItem *item, NRRectL * /*area*/) +static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/) { - //NRArenaGroup *group = NR_ARENA_GROUP(item); + NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); + + cairo_save(ct); + ink_cairo_transform(ct, ggroup->ctm); - guint ret = item->state; + for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) { + NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); + Geom::PathVector const &pathv = *g->font->PathVector(g->glyph); - // Render children fill mask - /* - for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, pb); - if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret; - }*/ + cairo_save(ct); + ink_cairo_transform(ct, g->g_transform); + feed_pathvector_to_cairo(ct, pathv); + cairo_fill(ct); + cairo_restore(ct); + } + cairo_restore(ct); - return ret; + return item->state; } static NRArenaItem * diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index d1e6869aa..5f11c1a6b 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -237,7 +237,6 @@ nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) unsigned int ret = item->state; - /* Just compose children into parent buffer */ for (NRArenaItem *child = group->children; child != NULL; child = child->next) { ret = nr_arena_item_invoke_clip (ct, child, area); if (ret & NR_ARENA_ITEM_STATE_INVALID) break; diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 9c7af1077..534591f82 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -392,119 +392,138 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area using namespace Inkscape; - // clipping and masks - unsigned int state; - - cairo_t *this_ct = ct; - NRRectL *this_area = const_cast(area); + unsigned state; + unsigned retstate; + // determine whether this shape needs intermediate rendering. bool needs_intermediate_rendering = false; bool &nir = needs_intermediate_rendering; bool needs_opacity = (item->opacity != 255 && !item->render_opacity); // this item needs an intermediate rendering if: - nir |= (item->mask != NULL); // 1. it has a mask - nir |= (item->filter != NULL && filter); // 2. it has a filter - nir |= needs_opacity; // 3. it is non-opaque + nir |= (item->clip != NULL); // 1. it has a clipping path + nir |= (item->mask != NULL); // 2. it has a mask + nir |= (item->filter != NULL && filter); // 3. it has a filter + nir |= needs_opacity; // 4. it is non-opaque double opacity = static_cast(item->opacity) / 255.0; - if (needs_intermediate_rendering) { - cairo_surface_t *intermediate = cairo_surface_create_similar( - cairo_get_target(ct), CAIRO_CONTENT_COLOR_ALPHA, - carea.x1 - carea.x0, carea.y1 - carea.y0); - this_ct = cairo_create(intermediate); - cairo_translate(this_ct, -carea.x0, -carea.y0); - this_area = &carea; - cairo_surface_destroy(intermediate); // the surface will be held in memory by this_ct - } else { - cairo_reference(this_ct); - } - - // The pipeline needs to be different for filters. - // First we render the item into an intermediate surface. Then the filter rotates - // the surface to user coordinates (if necessary) and runs the rendering. - // Once that's done we retrieve the result, rotating it back to screen coords. - // Clipping and masking happens after the filter result is ready. - if (item->filter && filter) { - } - - Cairo::Context cct(this_ct, true); - Cairo::Context base_ct(ct); - Cairo::RefPtr mask; - CairoSave clipsave(ct); // RAII for save / restore - CairoGroup maskgroup(this_ct); // RAII for push_group / pop_group - CairoGroup drawgroup(this_ct); - CairoGroup maskopacitygroup(this_ct); + /* How the rendering is done. + * + * There is one intermediate surface onto which the object is rendered. + * Clipping, masking and opacity are done with a mask. + * Here are the algorithms: + * a) no clip, no mask, no opacity: direct rendering. + * b) clip, no mask, no opacity: clipping path is rendered and used as a mask. + * c) no clip, mask, no opacity: mask is rendered, luminance is converted to alpha, + * then it is used as a mask. + * d) no clip, no mask, opacity: paint_with_alpha is used. + * e) clip, mask, no opacity: mask is rendered and its luminance is converted to alpha, + * then the clip is composited with it using the IN operator, the result is used + * as a mask. + * f) clip, no mask, opacity: clipping path is rendered with alpha corresponding + * to the opacity value and used as a mask. + * g) no clip, mask, opacity: like e), but the converted mask is composited with + * an uniform fill + * h) clip, mask, opacity: converted mask is composited with the clipping path + * rendered with alpha corresponding to the opacity using the IN operator + */ - // always clip the base context, not the one on the intermediate surface - // this is because filters must be done before clipping - if (item->clip) { - clipsave.save(); - state = nr_arena_item_invoke_clip(ct, item->clip, const_cast(area)); + // handle case a). + if (!needs_intermediate_rendering) { + state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { item->state |= NR_ARENA_ITEM_STATE_INVALID; return item->state; } - base_ct.clip(); + return item->state | NR_ARENA_ITEM_STATE_RENDER; } - // render mask on the intermediate context and store it + cairo_surface_t *intermediate = cairo_surface_create_similar( + cairo_get_target(ct), CAIRO_CONTENT_COLOR_ALPHA, + carea.x1 - carea.x0, carea.y1 - carea.y0); + cairo_t *ict = cairo_create(intermediate); + cairo_translate(ict, -carea.x0, -carea.y0); + + // now ict draws on the intermediate surface and carea is its area. + // 1. Render the mask if present. Otherwise initialize the intermediate surface to opaque. if (item->mask) { - maskgroup.push_with_content(CAIRO_CONTENT_COLOR_ALPHA); - // handle opacity of a masked object by composing it with the mask - if (needs_opacity) { - maskopacitygroup.push(); - } - state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (this_ct, item->mask, this_area, pb, flags); + state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, &carea, NULL, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; + retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); + goto cleanup; } - if (needs_opacity) { - maskopacitygroup.pop_to_source(); - cct.paint_with_alpha(opacity); + ink_cairo_surface_filter(intermediate, intermediate, MaskLuminanceToAlpha()); + } else { + cairo_set_source_rgba(ict, 0,0,0,1); + cairo_paint(ict); + } + + // 2. Render clipping path and composite it with mask + if (item->clip) { + cairo_push_group_with_content(ict, CAIRO_CONTENT_ALPHA); + cairo_set_source_rgba(ict, 0,0,0,opacity); + // Since clip can be combined with opacity, the result could be incorrect + // for overlapping children. To fix this we use the SOURCE operator + // instead of the default OVER + cairo_set_operator(ict, CAIRO_OPERATOR_SOURCE); + state = nr_arena_item_invoke_clip(ict, item->clip, const_cast(area)); + cairo_pop_group_to_source(ict); + if (state & NR_ARENA_ITEM_STATE_INVALID) { + retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); + goto cleanup; } - mask = maskgroup.popmm(); - // convert luminance to alpha - cairo_pattern_t *p = mask->cobj(); - cairo_surface_t *s; - cairo_pattern_get_surface(p, &s); - ink_cairo_surface_filter(s, s, MaskLuminanceToAlpha()); + cairo_set_operator(ict, CAIRO_OPERATOR_IN); + cairo_paint(ict); + cairo_set_operator(ict, CAIRO_OPERATOR_OVER); } - // render the object (possibly to the intermediate surface) - state = NR_ARENA_ITEM_VIRTUAL (item, render) (this_ct, item, this_area, pb, flags); + // 3. Render object itself + cairo_push_group_with_content(ict, CAIRO_CONTENT_COLOR_ALPHA); + state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, &carea, pb, flags); + cairo_pop_group_to_source(ict); if (state & NR_ARENA_ITEM_STATE_INVALID) { - /* Clean up and return error */ - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; + retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); + goto cleanup; } - // apply filter + // 4. Apply filter if (item->filter && filter) { + // TODO: creating the Cairo context here only to pass it to the filter renderer, + // which calls cairo_get_target almost immediately, is rather silly. + // See whether creating the context can be avoided. + // Could also be fixed in Cairo by fixing cairo_get_target() to return + // the intermediate surface when a group is pushed. + cairo_pattern_t *obj = cairo_get_source(ict); + cairo_surface_t *objs; + cairo_pattern_get_surface(obj, &objs); + cairo_t *tct = cairo_create(objs); + cairo_translate(tct, -carea.x0, -carea.y0); NRRectL bgarea(item->arena->canvasarena->cache_area); - item->filter->render(item, ct, &bgarea, this_ct, &carea); + item->filter->render(item, ct, &bgarea, tct, &carea); + cairo_destroy(tct); } - if (needs_intermediate_rendering) { - cairo_surface_t *intermediate = cairo_get_target(this_ct); - cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0); - if (mask) { - cairo_mask(ct, mask->cobj()); - // opacity of masked objects is handled by premultiplying the mask - } else { - // opacity of non-masked objects must be rendered explicitly - if (needs_opacity) { - cairo_paint_with_alpha(ct, opacity); - } else { - cairo_paint(ct); - } - } - cairo_set_source_rgba(ct,0,0,0,0); + // 5. Render object inside the composited mask + clip + cairo_set_operator(ict, CAIRO_OPERATOR_IN); + if (needs_opacity && !item->clip) { + cairo_paint_with_alpha(ict, opacity); + } else { + cairo_paint(ict); } - return item->state | NR_ARENA_ITEM_STATE_RENDER; + // 6. Paint the completed rendering onto the base context + cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0); + cairo_paint(ct); + cairo_set_source_rgba(ct, 0,0,0,0); + + retstate = item->state | NR_ARENA_ITEM_STATE_RENDER; + + cleanup: + cairo_destroy(ict); + cairo_surface_destroy(intermediate); + + return retstate; } unsigned int @@ -530,15 +549,34 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) (&item->bbox)->y0, (&item->bbox)->x1, (&item->bbox)->y1); #endif + unsigned retstate = 0; + + // The item itself has a clipping path + // Render the clipping path onto a temporary surface, then composite it with the item + // using the IN operator + if (item->clip) { + cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); + // The source could have had opacity set, but push_group implicitly saves state + cairo_set_source_rgba(ct, 0,0,0,1); + nr_arena_item_invoke_clip(ct, item->clip, area); + } + if (item->visible && nr_rect_l_test_intersect_ptr(area, &item->bbox)) { /* Need render that item */ if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) { - return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> + retstate = ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> clip (ct, item, area); } } + + if (item->clip) { + cairo_pop_group_to_source(ct); + cairo_set_operator(ct, CAIRO_OPERATOR_IN); + cairo_paint(ct); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + } - return item->state; + return retstate; } NRArenaItem * diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index ff87b5134..9bece05b5 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -396,22 +396,21 @@ nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/) { - guint result = 0; - - // NOTE: for now this is incorrect, because it doesn't honor clip-rule, - // and will be incorrect for nested clipping paths. NRArenaShape *shape = NR_ARENA_SHAPE(item); if (!shape->curve) { - result = item->state; - } else { - cairo_save(ct); - ink_cairo_transform(ct, shape->ctm); - feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); - cairo_restore(ct); - - result = item->state; + return item->state; } - return result; + + // TODO: Handling of the clip-rule property / CSS attribute. + // Once the required bits are in SPStyle, this is as trivial as adding a single + // call to cairo_set_fill_rule() before cairo_fill(). + cairo_save(ct); + ink_cairo_transform(ct, shape->ctm); + feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); + cairo_fill(ct); + cairo_restore(ct); + + return item->state; } static NRArenaItem * -- cgit v1.2.3 From 3099a49e82622b42547088666099f33d0d55b1ad Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 10 Jul 2011 05:33:59 +0200 Subject: Implement handling of the clip-rule property. Partially based on a patch by Andrew Lutomirski. Fixed bugs: - https://launchpad.net/bugs/171243 (bzr r10347.1.8) --- src/display/nr-arena-glyphs.cpp | 10 +++++++++- src/display/nr-arena-group.cpp | 14 +++++++++++++- src/display/nr-arena-shape.cpp | 12 +++++++++--- 3 files changed, 31 insertions(+), 5 deletions(-) (limited to 'src/display') diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index 185551d31..b76e87a78 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -360,6 +360,14 @@ static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, N NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); cairo_save(ct); + // handle clip-rule + if (ggroup->style) { + if (ggroup->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { + cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD); + } else { + cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING); + } + } ink_cairo_transform(ct, ggroup->ctm); for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) { @@ -369,9 +377,9 @@ static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, N cairo_save(ct); ink_cairo_transform(ct, g->g_transform); feed_pathvector_to_cairo(ct, pathv); - cairo_fill(ct); cairo_restore(ct); } + cairo_fill(ct); cairo_restore(ct); return item->state; diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 5f11c1a6b..714c4ecff 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -12,6 +12,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include "display/canvas-bpath.h" #include "display/nr-arena-group.h" #include "display/nr-filter.h" #include "display/nr-filter-types.h" @@ -234,14 +235,25 @@ static unsigned int nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) { NRArenaGroup *group = NR_ARENA_GROUP (item); - unsigned int ret = item->state; + cairo_save(ct); + + // handle clip-rule + if (group->style) { + if (group->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { + cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD); + } else { + cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING); + } + } + for (NRArenaItem *child = group->children; child != NULL; child = child->next) { ret = nr_arena_item_invoke_clip (ct, child, area); if (ret & NR_ARENA_ITEM_STATE_INVALID) break; } + cairo_restore(ct); return ret; } diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index 9bece05b5..6d65611bf 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -21,6 +21,7 @@ #include <2geom/svg-path-parser.h> #include "display/cairo-utils.h" #include "display/canvas-arena.h" +#include "display/canvas-bpath.h" #include "display/curve.h" #include "display/nr-arena.h" #include "display/nr-arena-shape.h" @@ -401,10 +402,15 @@ static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*are return item->state; } - // TODO: Handling of the clip-rule property / CSS attribute. - // Once the required bits are in SPStyle, this is as trivial as adding a single - // call to cairo_set_fill_rule() before cairo_fill(). cairo_save(ct); + // handle clip-rule + if (shape->style) { + if (shape->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { + cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD); + } else { + cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING); + } + } ink_cairo_transform(ct, shape->ctm); feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); cairo_fill(ct); -- cgit v1.2.3 From 0d0a5d5453e43fb95e7ff54a59666f72b1c3178d Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 10 Jul 2011 05:37:31 +0200 Subject: Remove irrelevant clip-rule handling bit from NRArenaGroup. (bzr r10347.1.9) --- src/display/nr-arena-group.cpp | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'src/display') diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 714c4ecff..1a67a8404 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -237,23 +237,11 @@ nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) NRArenaGroup *group = NR_ARENA_GROUP (item); unsigned int ret = item->state; - cairo_save(ct); - - // handle clip-rule - if (group->style) { - if (group->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { - cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD); - } else { - cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING); - } - } - for (NRArenaItem *child = group->children; child != NULL; child = child->next) { ret = nr_arena_item_invoke_clip (ct, child, area); if (ret & NR_ARENA_ITEM_STATE_INVALID) break; } - cairo_restore(ct); return ret; } -- cgit v1.2.3 From d35cc479f65a013531ca49b53af8dc9e32671c81 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Mon, 11 Jul 2011 01:05:04 +0200 Subject: Simplify rendering of masked / clipped / translucent items. Handle nested clipping paths correctly. (bzr r10347.1.10) --- src/display/nr-arena-item.cpp | 105 ++++++++++++++++++----------------------- src/display/nr-filter-slot.cpp | 2 +- src/display/nr-filter.cpp | 2 +- 3 files changed, 48 insertions(+), 61 deletions(-) (limited to 'src/display') diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 534591f82..f3de7a66a 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -410,26 +410,17 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area /* How the rendering is done. * - * There is one intermediate surface onto which the object is rendered. - * Clipping, masking and opacity are done with a mask. - * Here are the algorithms: - * a) no clip, no mask, no opacity: direct rendering. - * b) clip, no mask, no opacity: clipping path is rendered and used as a mask. - * c) no clip, mask, no opacity: mask is rendered, luminance is converted to alpha, - * then it is used as a mask. - * d) no clip, no mask, opacity: paint_with_alpha is used. - * e) clip, mask, no opacity: mask is rendered and its luminance is converted to alpha, - * then the clip is composited with it using the IN operator, the result is used - * as a mask. - * f) clip, no mask, opacity: clipping path is rendered with alpha corresponding - * to the opacity value and used as a mask. - * g) no clip, mask, opacity: like e), but the converted mask is composited with - * an uniform fill - * h) clip, mask, opacity: converted mask is composited with the clipping path - * rendered with alpha corresponding to the opacity using the IN operator + * Clipping, masking and opacity are done by rendering them to a surface + * and then compositing the object's rendering onto it with the IN operator. + * The object itself is rendered to a group. + * + * Opacity is done by rendering the clipping path with an alpha + * value corresponding to the opacity. If there is no clipping path, + * the entire intermediate surface is painted with alpha corresponding + * to the opacity value. */ - // handle case a). + // short-circuit the simple case. if (!needs_intermediate_rendering) { state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { @@ -440,82 +431,74 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area } cairo_surface_t *intermediate = cairo_surface_create_similar( - cairo_get_target(ct), CAIRO_CONTENT_COLOR_ALPHA, + cairo_get_group_target(ct), CAIRO_CONTENT_COLOR_ALPHA, carea.x1 - carea.x0, carea.y1 - carea.y0); cairo_t *ict = cairo_create(intermediate); cairo_translate(ict, -carea.x0, -carea.y0); - // now ict draws on the intermediate surface and carea is its area. - // 1. Render the mask if present. Otherwise initialize the intermediate surface to opaque. - if (item->mask) { - state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, &carea, NULL, flags); + // 1. Render clipping path with alpha = opacity. + cairo_set_source_rgba(ict, 0,0,0,opacity); + // Since clip can be combined with opacity, the result could be incorrect + // for overlapping clip children. To fix this we use the SOURCE operator + // instead of the default OVER. + cairo_set_operator(ict, CAIRO_OPERATOR_SOURCE); + if (item->clip) { + state = nr_arena_item_invoke_clip(ict, item->clip, const_cast(area)); if (state & NR_ARENA_ITEM_STATE_INVALID) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; } - ink_cairo_surface_filter(intermediate, intermediate, MaskLuminanceToAlpha()); } else { - cairo_set_source_rgba(ict, 0,0,0,1); + // if there is no clipping path, fill the entire surface with alpha = opacity. cairo_paint(ict); } + // reset back to default + cairo_set_operator(ict, CAIRO_OPERATOR_OVER); - // 2. Render clipping path and composite it with mask - if (item->clip) { - cairo_push_group_with_content(ict, CAIRO_CONTENT_ALPHA); - cairo_set_source_rgba(ict, 0,0,0,opacity); - // Since clip can be combined with opacity, the result could be incorrect - // for overlapping children. To fix this we use the SOURCE operator - // instead of the default OVER - cairo_set_operator(ict, CAIRO_OPERATOR_SOURCE); - state = nr_arena_item_invoke_clip(ict, item->clip, const_cast(area)); - cairo_pop_group_to_source(ict); + // 2. Render the mask if present and compose it with the clipping path + opacity. + if (item->mask) { + cairo_push_group(ict); + state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, &carea, NULL, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; } + cairo_surface_t *mask_s = cairo_get_group_target(ict); + // Convert mask's luminance to alpha + ink_cairo_surface_filter(mask_s, mask_s, MaskLuminanceToAlpha()); + cairo_pop_group_to_source(ict); cairo_set_operator(ict, CAIRO_OPERATOR_IN); cairo_paint(ict); cairo_set_operator(ict, CAIRO_OPERATOR_OVER); } - // 3. Render object itself - cairo_push_group_with_content(ict, CAIRO_CONTENT_COLOR_ALPHA); + // 3. Render object itself. + cairo_push_group(ict); state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, &carea, pb, flags); - cairo_pop_group_to_source(ict); if (state & NR_ARENA_ITEM_STATE_INVALID) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; } - // 4. Apply filter + // 4. Apply filter. if (item->filter && filter) { - // TODO: creating the Cairo context here only to pass it to the filter renderer, - // which calls cairo_get_target almost immediately, is rather silly. - // See whether creating the context can be avoided. - // Could also be fixed in Cairo by fixing cairo_get_target() to return - // the intermediate surface when a group is pushed. - cairo_pattern_t *obj = cairo_get_source(ict); - cairo_surface_t *objs; - cairo_pattern_get_surface(obj, &objs); - cairo_t *tct = cairo_create(objs); - cairo_translate(tct, -carea.x0, -carea.y0); NRRectL bgarea(item->arena->canvasarena->cache_area); - item->filter->render(item, ct, &bgarea, tct, &carea); - cairo_destroy(tct); + item->filter->render(item, ct, &bgarea, ict, &carea); + // Note that because the object was rendered to a group, + // the internals of the filter need to use cairo_get_group_target() + // instead of cairo_get_target(). } // 5. Render object inside the composited mask + clip + cairo_pop_group_to_source(ict); cairo_set_operator(ict, CAIRO_OPERATOR_IN); - if (needs_opacity && !item->clip) { - cairo_paint_with_alpha(ict, opacity); - } else { - cairo_paint(ict); - } + cairo_paint(ict); // 6. Paint the completed rendering onto the base context cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0); cairo_paint(ct); cairo_set_source_rgba(ct, 0,0,0,0); + // the call above is to clear a ref on the intermediate surface held by ct retstate = item->state | NR_ARENA_ITEM_STATE_RENDER; @@ -551,14 +534,16 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) unsigned retstate = 0; - // The item itself has a clipping path - // Render the clipping path onto a temporary surface, then composite it with the item + // The item used as the clipping path itself has a clipping path. + // Render this item's clipping path onto a temporary surface, then composite it with the item // using the IN operator if (item->clip) { cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); - // The source could have had opacity set, but push_group implicitly saves state + cairo_save(ct); cairo_set_source_rgba(ct, 0,0,0,1); nr_arena_item_invoke_clip(ct, item->clip, area); + cairo_restore(ct); + cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); } if (item->visible && nr_rect_l_test_intersect_ptr(area, &item->bbox)) { @@ -573,7 +558,9 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) cairo_pop_group_to_source(ct); cairo_set_operator(ct, CAIRO_OPERATOR_IN); cairo_paint(ct); + cairo_pop_group_to_source(ct); cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); } return retstate; diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index ce07ff086..3464fda66 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -156,7 +156,7 @@ cairo_surface_t *FilterSlot::_get_transformed_background() { Geom::Affine trans = _units.get_matrix_display2pb(); - cairo_surface_t *bg = cairo_get_target(_background_ct); + cairo_surface_t *bg = cairo_get_group_target(_background_ct); cairo_surface_t *tbg = cairo_surface_create_similar( bg, cairo_surface_get_content(bg), _slot_w, _slot_h); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 10b4084ed..963d98654 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -160,7 +160,7 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea } } - FilterSlot slot(const_cast(item), bgct, bgarea, cairo_get_target(graphic), area, units); + FilterSlot slot(const_cast(item), bgct, bgarea, cairo_get_group_target(graphic), area, units); slot.set_quality(filterquality); slot.set_blurquality(blurquality); -- cgit v1.2.3 From d776f783e99f70029d1ec8d6c938468d7e220de0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 12 Jul 2011 03:18:44 +0200 Subject: Compute different bounding boxes in outline mode to fix partial rendering of objects where the clipping path is much larger than the base object or vice versa. Fixes LP #177687. Fixed bugs: - https://launchpad.net/bugs/177687 (bzr r10347.1.11) --- src/display/nr-arena-group.cpp | 7 +-- src/display/nr-arena-item.cpp | 115 ++++++++++++++++++++++------------------- 2 files changed, 65 insertions(+), 57 deletions(-) (limited to 'src/display') diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 1a67a8404..1d552fbc2 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -13,9 +13,11 @@ */ #include "display/canvas-bpath.h" +#include "display/nr-arena.h" #include "display/nr-arena-group.h" #include "display/nr-filter.h" #include "display/nr-filter-types.h" +#include "display/rendermode.h" #include "style.h" #include "sp-filter.h" #include "sp-filter-reference.h" @@ -164,10 +166,9 @@ 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; + bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); for (NRArenaItem *child = group->children; child != NULL; child = child->next) { NRGC cgc(gc); @@ -180,7 +181,7 @@ nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int item->bbox = NR_RECT_L_EMPTY; for (NRArenaItem *child = group->children; child != NULL; child = child->next) { if (child->visible) - nr_rect_l_union (&item->bbox, &item->bbox, &child->drawbox); + nr_rect_l_union (&item->bbox, &item->bbox, outline ? &child->bbox : &child->drawbox); } } diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index f3de7a66a..7e19b9f52 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -215,6 +215,7 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, { NRGC childgc (gc); bool filter = (item->arena->rendermode == Inkscape::RENDERMODE_NORMAL); + bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), @@ -243,7 +244,7 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, return item->state; /* Test whether to return immediately */ if (area && (item->state & NR_ARENA_ITEM_STATE_BBOX)) { - if (!nr_rect_l_test_intersect_ptr(area, &item->drawbox)) + if (!nr_rect_l_test_intersect_ptr(area, outline ? &item->bbox : &item->drawbox)) return item->state; } @@ -276,8 +277,6 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, } else { memcpy(&item->drawbox, &item->bbox, sizeof(item->bbox)); } - // fixme: to fix the display glitches, in outline mode bbox must be a combination of - // full item bbox and its clip and mask (after we have the API to get these) /* Clipping */ if (item->clip) { @@ -289,8 +288,12 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, item->state |= NR_ARENA_ITEM_STATE_INVALID; return item->state; } - // for clipping, we need geometric bbox - nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->clip->bbox); + if (outline) { + nr_rect_l_union(&item->bbox, &item->bbox, &item->clip->bbox); + } else { + // for clipping, we need geometric bbox + nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->clip->bbox); + } } /* Masking */ if (item->mask) { @@ -299,8 +302,12 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, item->state |= NR_ARENA_ITEM_STATE_INVALID; return item->state; } - // for masking, we need full drawbox of mask - nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->mask->drawbox); + if (outline) { + nr_rect_l_union(&item->bbox, &item->bbox, &item->mask->bbox); + } else { + // for masking, we need full drawbox of mask + nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->mask->drawbox); + } } // now that we know drawbox, dirty the corresponding rect on canvas: @@ -350,18 +357,14 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area if (!item->visible) return item->state | NR_ARENA_ITEM_STATE_RENDER; - // carea is the bounding box for intermediate rendering. - // NOTE: carea might be larger than area, because of filter effects. - NRRectL carea; - nr_rect_l_intersect (&carea, area, &item->drawbox); - if (nr_rect_l_test_empty(carea)) - return item->state | NR_ARENA_ITEM_STATE_RENDER; - if (item->filter && filter) { - item->filter->area_enlarge (carea, item); - nr_rect_l_intersect (&carea, &carea, &item->drawbox); - } - if (outline) { + // intersect with bbox rather than drawbox, as we want to render things outside + // of the clipping path as well + NRRectL carea; + nr_rect_l_intersect (&carea, area, &item->bbox); + if (nr_rect_l_test_empty(carea)) + return item->state | NR_ARENA_ITEM_STATE_RENDER; + // No caching in outline mode for now; investigate if it really gives any advantage with cairo. // Also no attempts to clip anything; just render everything: item, clip, mask // First, render the object itself @@ -389,6 +392,17 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area return item->state | NR_ARENA_ITEM_STATE_RENDER; } + + // carea is the bounding box for intermediate rendering. + // NOTE: carea might be larger than area, because of filter effects. + NRRectL carea; + nr_rect_l_intersect (&carea, area, &item->drawbox); + if (nr_rect_l_test_empty(carea)) + return item->state | NR_ARENA_ITEM_STATE_RENDER; + if (item->filter && filter) { + item->filter->area_enlarge (carea, item); + nr_rect_l_intersect (&carea, &carea, &item->drawbox); + } using namespace Inkscape; @@ -515,16 +529,6 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NR_ARENA_ITEM_STATE_INVALID); - /* we originally short-circuited if the object state included - * NR_ARENA_ITEM_STATE_CLIP (and showed a warning on the console); - * anyone know why we stopped doing so? - */ - /*nr_return_val_if_fail ((pb->area.x1 - pb->area.x0) >= - (area->x1 - area->x0), - NR_ARENA_ITEM_STATE_INVALID); - nr_return_val_if_fail ((pb->area.y1 - pb->area.y0) >= - (area->y1 - area->y0), - NR_ARENA_ITEM_STATE_INVALID);*/ #ifdef NR_ARENA_ITEM_VERBOSE printf ("Invoke clip by %p: %d %d - %d %d, item bbox %d %d - %d %d\n", @@ -533,34 +537,36 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) #endif unsigned retstate = 0; - - // The item used as the clipping path itself has a clipping path. - // Render this item's clipping path onto a temporary surface, then composite it with the item - // using the IN operator - if (item->clip) { - cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); - cairo_save(ct); - cairo_set_source_rgba(ct, 0,0,0,1); - nr_arena_item_invoke_clip(ct, item->clip, area); - cairo_restore(ct); - cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); - } + + // don't bother if the object does not implement clipping (e.g. NRArenaImage) + if (!((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) + return retstate; if (item->visible && nr_rect_l_test_intersect_ptr(area, &item->bbox)) { - /* Need render that item */ - if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) { - retstate = ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> - clip (ct, item, area); + // The item used as the clipping path itself has a clipping path. + // Render this item's clipping path onto a temporary surface, then composite it with the item + // using the IN operator + if (item->clip) { + cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); + cairo_save(ct); + cairo_set_source_rgba(ct, 0,0,0,1); + nr_arena_item_invoke_clip(ct, item->clip, area); + cairo_restore(ct); + cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); + } + + // rasterize the clipping path + retstate = ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> + clip (ct, item, area); + + if (item->clip) { + cairo_pop_group_to_source(ct); + cairo_set_operator(ct, CAIRO_OPERATOR_IN); + cairo_paint(ct); + cairo_pop_group_to_source(ct); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); } - } - - if (item->clip) { - cairo_pop_group_to_source(ct); - cairo_set_operator(ct, CAIRO_OPERATOR_IN); - cairo_paint(ct); - cairo_pop_group_to_source(ct); - cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); - cairo_paint(ct); } return retstate; @@ -624,7 +630,8 @@ nr_arena_item_request_render (NRArenaItem *item) nr_return_if_fail (item != NULL); nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - nr_arena_request_render_rect (item->arena, &item->drawbox); + bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); + nr_arena_request_render_rect (item->arena, outline ? &item->bbox : &item->drawbox); } /* Public */ -- cgit v1.2.3 From 7a6b02a54a5516ff17662352903a928f5f5f7afb Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 13 Jul 2011 23:09:35 +0200 Subject: Fix crashes during offscreen rendering, part 1 (bzr r10347.1.12) --- src/display/nr-arena-item.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/display') diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 7e19b9f52..9ca5a7463 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -496,7 +496,15 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area // 4. Apply filter. if (item->filter && filter) { - NRRectL bgarea(item->arena->canvasarena->cache_area); + // HACK: SPCanvasArena doesn't exist when this is called for offscreen rendering + // Proper fix: call this function with a drawing context class + // that contains information about the surface's bounds + NRRectL bgarea; + if (flags & NR_ARENA_ITEM_RENDER_NO_CACHE || !item->arena->canvasarena) { + bgarea = carea; + } else { + bgarea = NRRectL(item->arena->canvasarena->cache_area); + } item->filter->render(item, ct, &bgarea, ict, &carea); // Note that because the object was rendered to a group, // the internals of the filter need to use cairo_get_group_target() -- cgit v1.2.3 From 019aaf9cd028184da90bc8d7dd558ce14b4e7862 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 14 Jul 2011 20:55:37 +0200 Subject: Remove useless pixmap_gc variable (bzr r10347.1.14) --- src/display/sp-canvas.cpp | 27 ++++++--------------------- src/display/sp-canvas.h | 5 +---- 2 files changed, 7 insertions(+), 25 deletions(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index f6446bdd7..d7f34969f 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1061,7 +1061,7 @@ sp_canvas_init (SPCanvas *canvas) #if ENABLE_LCMS canvas->enable_cms_display_adj = false; - canvas->cms_key = new Glib::ustring(""); + new (&canvas->cms_key) Glib::ustring(""); #endif // ENABLE_LCMS canvas->is_scrolling = false; @@ -1121,6 +1121,8 @@ sp_canvas_destroy (GtkObject *object) shutdown_transients (canvas); + canvas->cms_key.~ustring(); + if (GTK_OBJECT_CLASS (canvas_parent_class)->destroy) (* GTK_OBJECT_CLASS (canvas_parent_class)->destroy) (object); } @@ -1150,8 +1152,6 @@ sp_canvas_new_aa (void) static void sp_canvas_realize (GtkWidget *widget) { - SPCanvas *canvas = SP_CANVAS (widget); - GdkWindowAttr attributes; attributes.window_type = GDK_WINDOW_CHILD; attributes.x = widget->allocation.x; @@ -1187,8 +1187,6 @@ sp_canvas_realize (GtkWidget *widget) widget->style = gtk_style_attach (widget->style, widget->window); gtk_widget_set_realized (widget, TRUE); - - canvas->pixmap_gc = gdk_gc_new (SP_CANVAS_WINDOW (canvas)); } /** @@ -1205,9 +1203,6 @@ sp_canvas_unrealize (GtkWidget *widget) shutdown_transients (canvas); - gdk_gc_destroy (canvas->pixmap_gc); - canvas->pixmap_gc = NULL; - if (GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (* GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (widget); } @@ -1626,7 +1621,7 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event) if (event->window != SP_CANVAS_WINDOW (canvas)) return FALSE; - if (canvas->pixmap_gc == NULL) // canvas being deleted + if (canvas->root == NULL) // canvas being deleted return FALSE; canvas->state = event->state; @@ -1694,7 +1689,7 @@ static void sp_canvas_paint_single_buffer(SPCanvas *canvas, int x0, int y0, int Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool fromDisplay = prefs->getBool( "/options/displayprofile/from_display"); if ( fromDisplay ) { - transf = Inkscape::CMSSystem::getDisplayPer( canvas->cms_key ? *(canvas->cms_key) : "" ); + transf = Inkscape::CMSSystem::getDisplayPer( canvas->cms_key ); } else { transf = Inkscape::CMSSystem::getDisplayTransform(); } @@ -1881,16 +1876,6 @@ sp_canvas_paint_rect (SPCanvas *canvas, int xx0, int yy0, int xx1, int yy1) rect.x1 = MIN (rect.x1, canvas->x0/*draw_x1*/ + GTK_WIDGET (canvas)->allocation.width); rect.y1 = MIN (rect.y1, canvas->y0/*draw_y1*/ + GTK_WIDGET (canvas)->allocation.height); -#ifdef DEBUG_REDRAW - // paint the area to redraw yellow - gdk_rgb_gc_set_foreground (canvas->pixmap_gc, 0xFFFF00); - gdk_draw_rectangle (SP_CANVAS_WINDOW (canvas), - canvas->pixmap_gc, - TRUE, - rect.x0 - canvas->x0, rect.y0 - canvas->y0, - rect.x1 - rect.x0, rect.y1 - rect.y0); -#endif - PaintRectSetup setup; setup.canvas = canvas; @@ -2088,7 +2073,7 @@ paint (SPCanvas *canvas) static int do_update (SPCanvas *canvas) { - if (!canvas->root || !canvas->pixmap_gc) // canvas may have already be destroyed by closing desktop during interrupted display! + if (!canvas->root) // canvas may have already be destroyed by closing desktop during interrupted display! return TRUE; if (canvas->drawing_disabled) diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 32747e7c5..f284afdf2 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -112,9 +112,6 @@ struct SPCanvas { int close_enough; - /* GC for temporary draw pixmap */ - GdkGC *pixmap_gc; - unsigned int need_update : 1; unsigned int need_redraw : 1; unsigned int need_repick : 1; @@ -143,7 +140,7 @@ struct SPCanvas { #if ENABLE_LCMS bool enable_cms_display_adj; - Glib::ustring* cms_key; + Glib::ustring cms_key; #endif // ENABLE_LCMS bool is_scrolling; -- cgit v1.2.3