X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fdisplay%2Fnr-filter-slot.cpp;h=7df9ab97931a7ce68ac1a92f3a012ca1fe3bdc4c;hb=50459c2f835dde920d4fedb7c99449ad96c3cbe7;hp=250aee10b8537b9661397d81e30cdf4b20bfe958;hpb=9a5352f6231f55c96d746cb1e674e6cfecdaa4bf;p=inkscape.git diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index 250aee10b..7df9ab979 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -1,5 +1,3 @@ -#define __NR_FILTER_SLOT_CPP__ - /* * A container class for filter slots. Allows for simple getting and * setting images in filter slots without having to bother with @@ -8,21 +6,69 @@ * Author: * Niko Kiirala * - * Copyright (C) 2006 Niko Kiirala + * Copyright (C) 2006,2007 Niko Kiirala * * Released under GNU GPL, read the file 'COPYING' for more information */ #include +#include #include "display/nr-arena-item.h" -#include "libnr/nr-pixblock.h" #include "display/nr-filter-types.h" +#include "display/nr-filter-gaussian.h" #include "display/nr-filter-slot.h" +#include "display/nr-filter-getalpha.h" +#include "display/nr-filter-units.h" +#include "display/pixblock-scaler.h" +#include "display/pixblock-transform.h" +#include "libnr/nr-pixblock.h" +#include "libnr/nr-blit.h" -namespace NR { +__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); +} + +__attribute__ ((const)) +inline static int _max2(const double a, const double b) { + if (a > b) + return (int)round(a); + else + return (int)round(b); +} + +__attribute__ ((const)) +inline static int _min2(const double a, const double b) { + if (a > b) + return (int)round(b); + else + return (int)round(a); +} + +namespace Inkscape { +namespace Filters { FilterSlot::FilterSlot(int slots, NRArenaItem const *item) + : _last_out(-1), + filterquality(FILTER_QUALITY_BEST), + blurquality(BLUR_QUALITY_BEST), + _arena_item(item) { _slot_count = ((slots > 0) ? slots : 2); _slot = new NRPixBlock*[_slot_count]; @@ -32,10 +78,6 @@ FilterSlot::FilterSlot(int slots, NRArenaItem const *item) _slot[i] = NULL; _slot_number[i] = NR_FILTER_SLOT_NOT_SET; } - - _last_out = -1; - - _arena_item = item; } FilterSlot::~FilterSlot() @@ -65,12 +107,11 @@ NRPixBlock *FilterSlot::get(int slot_nr) || slot_nr == NR_FILTER_STROKEPAINT)) { /* If needed, fetch background */ - if (slot_nr == NR_FILTER_BACKGROUNDIMAGE - || slot_nr == NR_FILTER_BACKGROUNDALPHA) - { + if (slot_nr == NR_FILTER_BACKGROUNDIMAGE) { NRPixBlock *pb; pb = nr_arena_item_get_background(_arena_item); if (pb) { + pb->empty = false; this->set(NR_FILTER_BACKGROUNDIMAGE, pb); } else { NRPixBlock *source = this->get(NR_FILTER_SOURCEGRAPHIC); @@ -87,33 +128,142 @@ NRPixBlock *FilterSlot::get(int slot_nr) pb->empty = FALSE; this->set(NR_FILTER_BACKGROUNDIMAGE, pb); } - } - /* If only a alpha channel is needed, strip it from full image */ - if (slot_nr == NR_FILTER_SOURCEALPHA) { - // TODO - } - if (slot_nr == NR_FILTER_BACKGROUNDALPHA) { + } else if (slot_nr == NR_FILTER_SOURCEALPHA) { + /* If only a alpha channel is needed, strip it from full image */ + NRPixBlock *src = get(NR_FILTER_SOURCEGRAPHIC); + NRPixBlock *sa = filter_get_alpha(src); + set(NR_FILTER_SOURCEALPHA, sa); + } else if (slot_nr == NR_FILTER_BACKGROUNDALPHA) { + NRPixBlock *src = get(NR_FILTER_BACKGROUNDIMAGE); + NRPixBlock *ba = filter_get_alpha(src); + set(NR_FILTER_BACKGROUNDALPHA, ba); + } else if (slot_nr == NR_FILTER_FILLPAINT) { + /* When a paint is needed, fetch it from arena item */ // TODO - } - /* When a paint is needed, fetch it from arena item */ - if (slot_nr == NR_FILTER_FILLPAINT) { - // TODO - } - if (slot_nr == NR_FILTER_STROKEPAINT) { + } else if (slot_nr == NR_FILTER_STROKEPAINT) { // TODO } } + if (_slot[index]) { + _slot[index]->empty = false; + } + assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr); return _slot[index]; } +void FilterSlot::get_final(int slot_nr, NRPixBlock *result) { + NRPixBlock *final_usr = get(slot_nr); + Geom::Matrix trans = units.get_matrix_pb2display(); + + int size = (result->area.x1 - result->area.x0) + * (result->area.y1 - result->area.y0) + * NR_PIXBLOCK_BPP(result); + memset(NR_PIXBLOCK_PX(result), 0, size); + + if (fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) { + if (filterquality == FILTER_QUALITY_BEST) { + NR::transform_bicubic(result, final_usr, trans); + } else { + NR::transform_nearest(result, final_usr, trans); + } + } else if (fabs(trans[0] - 1) > 1e-6 || fabs(trans[3] - 1) > 1e-6) { + NR::scale_bicubic(result, final_usr, trans); + } else { + nr_blit_pixblock_pixblock(result, final_usr); + } +} + void FilterSlot::set(int slot_nr, NRPixBlock *pb) { - int index = _get_index(slot_nr); + /* Unnamed slot is for saving filter primitive results, when parameter + * 'result' is not set. Only the filter immediately after this one + * can access unnamed results, so we don't have to worry about overwriting + * previous results in filter chain. On the other hand, we may not + * overwrite any other image with this one, because they might be + * accessed later on. */ + int index = ((slot_nr != NR_FILTER_SLOT_NOT_SET) + ? _get_index(slot_nr) + : _get_index(NR_FILTER_UNNAMED_SLOT)); assert(index >= 0); + // Unnamed slot is only for Inkscape::Filters::FilterSlot internal use. + assert(slot_nr != NR_FILTER_UNNAMED_SLOT); assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr); + if (slot_nr == NR_FILTER_SOURCEGRAPHIC || slot_nr == NR_FILTER_BACKGROUNDIMAGE) { + Geom::Matrix trans = units.get_matrix_display2pb(); + if (fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) { + NRPixBlock *trans_pb = new NRPixBlock; + int x0 = pb->area.x0; + int y0 = pb->area.y0; + int x1 = pb->area.x1; + int y1 = pb->area.y1; + int min_x = _min4(trans[0] * x0 + trans[2] * y0 + trans[4], + trans[0] * x0 + trans[2] * y1 + trans[4], + trans[0] * x1 + trans[2] * y0 + trans[4], + trans[0] * x1 + trans[2] * y1 + trans[4]); + int max_x = _max4(trans[0] * x0 + trans[2] * y0 + trans[4], + trans[0] * x0 + trans[2] * y1 + trans[4], + trans[0] * x1 + trans[2] * y0 + trans[4], + trans[0] * x1 + trans[2] * y1 + trans[4]); + int min_y = _min4(trans[1] * x0 + trans[3] * y0 + trans[5], + trans[1] * x0 + trans[3] * y1 + trans[5], + trans[1] * x1 + trans[3] * y0 + trans[5], + trans[1] * x1 + trans[3] * y1 + trans[5]); + int max_y = _max4(trans[1] * x0 + trans[3] * y0 + trans[5], + trans[1] * x0 + trans[3] * y1 + trans[5], + trans[1] * x1 + trans[3] * y0 + trans[5], + trans[1] * x1 + trans[3] * y1 + trans[5]); + + nr_pixblock_setup_fast(trans_pb, pb->mode, + min_x, min_y, + max_x, max_y, true); + if (trans_pb->size != NR_PIXBLOCK_SIZE_TINY && trans_pb->data.px == NULL) { + /* TODO: this gets hit occasionally. Worst case scenario: + * images are exported in horizontal stripes. One stripe + * is not too high, but can get thousands of pixels wide. + * Rotate this 45 degrees -> _huge_ image */ + g_warning("Memory allocation failed in Inkscape::Filters::FilterSlot::set (transform)"); + return; + } + if (filterquality == FILTER_QUALITY_BEST) { + NR::transform_bicubic(trans_pb, pb, trans); + } else { + NR::transform_nearest(trans_pb, pb, trans); + } + nr_pixblock_release(pb); + delete pb; + pb = trans_pb; + } else if (fabs(trans[0] - 1) > 1e-6 || fabs(trans[3] - 1) > 1e-6) { + NRPixBlock *trans_pb = new NRPixBlock; + + int x0 = pb->area.x0; + int y0 = pb->area.y0; + int x1 = pb->area.x1; + int y1 = pb->area.y1; + int min_x = _min2(trans[0] * x0 + trans[4], + trans[0] * x1 + trans[4]); + int max_x = _max2(trans[0] * x0 + trans[4], + trans[0] * x1 + trans[4]); + int min_y = _min2(trans[3] * y0 + trans[5], + trans[3] * y1 + trans[5]); + int max_y = _max2(trans[3] * y0 + trans[5], + trans[3] * y1 + trans[5]); + + nr_pixblock_setup_fast(trans_pb, pb->mode, + min_x, min_y, max_x, max_y, true); + if (trans_pb->size != NR_PIXBLOCK_SIZE_TINY && trans_pb->data.px == NULL) { + g_warning("Memory allocation failed in Inkscape::Filters::FilterSlot::set (scaling)"); + return; + } + NR::scale_bicubic(trans_pb, pb, trans); + nr_pixblock_release(pb); + delete pb; + pb = trans_pb; + } + } + if(_slot[index]) { nr_pixblock_release(_slot[index]); delete _slot[index]; @@ -127,11 +277,16 @@ int FilterSlot::get_slot_count() int seek = _slot_count; do { seek--; - } while (_slot[seek] == NULL); - + } while (!_slot[seek] && _slot_number[seek] == NR_FILTER_SLOT_NOT_SET); + return seek + 1; } +NRArenaItem const* FilterSlot::get_arenaitem() +{ + return _arena_item; +} + int FilterSlot::_get_index(int slot_nr) { assert(slot_nr >= 0 || @@ -141,7 +296,8 @@ int FilterSlot::_get_index(int slot_nr) slot_nr == NR_FILTER_BACKGROUNDIMAGE || slot_nr == NR_FILTER_BACKGROUNDALPHA || slot_nr == NR_FILTER_FILLPAINT || - slot_nr == NR_FILTER_STROKEPAINT); + slot_nr == NR_FILTER_STROKEPAINT || + slot_nr == NR_FILTER_UNNAMED_SLOT); int index = -1; if (slot_nr == NR_FILTER_SLOT_NOT_SET) { @@ -160,7 +316,7 @@ int FilterSlot::_get_index(int slot_nr) int seek = _slot_count; do { seek--; - } while (_slot[seek] == NULL && seek > 0); + } while ((seek >= 0) && (_slot_number[seek] == NR_FILTER_SLOT_NOT_SET)); /* If there is no space for more slots, create more space */ if (seek == _slot_count - 1) { NRPixBlock **new_slot = new NRPixBlock*[_slot_count * 2]; @@ -186,8 +342,25 @@ int FilterSlot::_get_index(int slot_nr) return index; } +void FilterSlot::set_units(FilterUnits const &units) { + this->units = units; +} + +void FilterSlot::set_quality(FilterQuality const q) { + filterquality = q; +} + +void FilterSlot::set_blurquality(int const q) { + blurquality = q; } +int FilterSlot::get_blurquality(void) { + return blurquality; +} + +} /* namespace Filters */ +} /* namespace Inkscape */ + /* Local Variables: mode:c++