X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fdisplay%2Fnr-filter.cpp;h=07c2649289b128fa9b9657ab3cd171ce4b390251;hb=daa122e632b9c06a0b6fb8971a41b2886d0e99cc;hp=328b5c12aac2bf297c8e572c070bfdda8b4127ec;hpb=1cb9a58ed7f1377b8b2757dd73d0429370e0cafa;p=inkscape.git diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 328b5c12a..07c264928 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -12,6 +12,7 @@ */ #include +#include #include "display/nr-filter.h" #include "display/nr-filter-primitive.h" @@ -19,6 +20,7 @@ #include "display/nr-filter-slot.h" #include "display/nr-filter-types.h" #include "display/pixblock-scaler.h" +#include "display/pixblock-transform.h" #include "display/nr-arena-item.h" #include "libnr/nr-pixblock.h" @@ -27,9 +29,33 @@ #include "libnr/nr-scale.h" #include "svg/svg-length.h" #include "sp-filter-units.h" +#if defined (SOLARIS_2_8) +#include "round.h" +using Inkscape::round; +#endif //#include "display/nr-arena-shape.h" +__attribute__ ((const)) +inline static int _max4(const double a, const double b, + const double c, const double d) { + double ret = a; + if (b > ret) ret = b; + if (c > ret) ret = c; + if (d > ret) ret = d; + return (int)round(ret); +} + +__attribute__ ((const)) +inline static int _min4(const double a, const double b, + const double c, const double d) { + double ret = a; + if (b < ret) ret = b; + if (c < ret) ret = c; + if (d < ret) ret = d; + return (int)round(ret); +} + namespace NR { Filter::Filter() @@ -85,13 +111,66 @@ Filter::~Filter() int Filter::render(NRArenaItem const *item, NRPixBlock *pb) { + if(!_primitive[0]) { // if there are no primitives, do nothing + return 0; + } + Matrix trans = *item->ctm; + Matrix paraller_trans = trans; + bool notparaller = false; FilterSlot slot(_slot_count, item); NRPixBlock *in = new NRPixBlock; - // First, if filter resolution is not set to automatic, we should - // scale the input image to correct resolution - if (_x_pixels >= 0) { + // If filter effects region is not paraller to viewport, + // we must first undo the rotation / shear. + // It will be redone after filtering. + // If there is only rotation and uniform scaling (zoom), let's skip this, + // as it will not make a difference with gaussian blur. + if ((fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) && + !(fabs(trans[0] - trans[3]) < 1e-6 && fabs(trans[1] + trans[2]) < 1e-6)) { + notparaller = true; + + // TODO: if filter resolution is specified, scaling should be set + // according to that + double scaling_factor = sqrt(trans.expansionX() * trans.expansionX() + + trans.expansionY() * trans.expansionY()); + scale scaling(scaling_factor, scaling_factor); + scale scaling_inv(1.0 / scaling_factor, 1.0 / scaling_factor); + trans *= scaling_inv; + paraller_trans.set_identity(); + paraller_trans *= scaling; + + Matrix itrans = trans.inverse(); + int x0 = pb->area.x0; + int y0 = pb->area.y0; + int x1 = pb->area.x1; + int y1 = pb->area.y1; + int min_x = _min4(itrans[0] * x0 + itrans[2] * y0 + itrans[4], + itrans[0] * x0 + itrans[2] * y1 + itrans[4], + itrans[0] * x1 + itrans[2] * y0 + itrans[4], + itrans[0] * x1 + itrans[2] * y1 + itrans[4]); + int max_x = _max4(itrans[0] * x0 + itrans[2] * y0 + itrans[4], + itrans[0] * x0 + itrans[2] * y1 + itrans[4], + itrans[0] * x1 + itrans[2] * y0 + itrans[4], + itrans[0] * x1 + itrans[2] * y1 + itrans[4]); + int min_y = _min4(itrans[1] * x0 + itrans[3] * y0 + itrans[5], + itrans[1] * x0 + itrans[3] * y1 + itrans[5], + itrans[1] * x1 + itrans[3] * y0 + itrans[5], + itrans[1] * x1 + itrans[3] * y1 + itrans[5]); + int max_y = _max4(itrans[1] * x0 + itrans[3] * y0 + itrans[5], + itrans[1] * x0 + itrans[3] * y1 + itrans[5], + itrans[1] * x1 + itrans[3] * y0 + itrans[5], + itrans[1] * x1 + itrans[3] * y1 + itrans[5]); + + nr_pixblock_setup_fast(in, pb->mode, + min_x, min_y, + max_x, max_y, true); + if (in->size != NR_PIXBLOCK_SIZE_TINY && in->data.px == NULL) // memory allocation failed + return 0; + transform_nearest(in, pb, itrans); + } else if (_x_pixels >= 0) { + // If filter resolution is not set to automatic, we should + // scale the input image to correct resolution /* If filter resolution is zero, the object should not be rendered */ if (_x_pixels == 0 || _y_pixels == 0) { int size = (pb->area.x1 - pb->area.x0) @@ -116,28 +195,26 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb) } if (y_len < 1) y_len = 1; nr_pixblock_setup_fast(in, pb->mode, 0, 0, x_len, y_len, true); - if (in->data.px == NULL) // memory allocation failed + if (in->size != NR_PIXBLOCK_SIZE_TINY && in->data.px == NULL) // memory allocation failed return 0; scale_bicubic(in, pb); scale res_scaling(x_len / (double)(pb->area.x1 - pb->area.x0), y_len / (double)(pb->area.y1 - pb->area.y0)); - trans *= res_scaling; + paraller_trans *= res_scaling; } else { // If filter resolution is automatic, just make copy of input image nr_pixblock_setup_fast(in, pb->mode, pb->area.x0, pb->area.y0, pb->area.x1, pb->area.y1, true); - if (in->data.px == NULL) // memory allocation failed + if (in->size != NR_PIXBLOCK_SIZE_TINY && in->data.px == NULL) // memory allocation failed return 0; nr_blit_pixblock_pixblock(in, pb); } slot.set(NR_FILTER_SOURCEGRAPHIC, in); in = NULL; // in is now handled by FilterSlot, we should not touch it - // TODO: loop through the primitives and render them one at a time - if(_primitive[0]) - _primitive[0]->render(slot, trans); - + // TODO: loop through ALL the primitives and render them one at a time + _primitive[0]->render(slot, paraller_trans); NRPixBlock *out = slot.get(_output_slot); // Clear the pixblock, where the output will be put @@ -147,9 +224,11 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb) * NR_PIXBLOCK_BPP(pb); memset(NR_PIXBLOCK_PX(pb), 0, size); - // If the filter resolution is automatic, just copy our final image - // to output pixblock, otherwise use bicubic scaling - if (_x_pixels < 0) { + if (notparaller) { + transform_nearest(pb, out, trans); + } else if (_x_pixels < 0) { + // If the filter resolution is automatic, just copy our final image + // to output pixblock, otherwise use bicubic scaling nr_blit_pixblock_pixblock(pb, out); } else { scale_bicubic(pb, out);