From: kiirala Date: Wed, 26 Jul 2006 17:31:16 +0000 (+0000) Subject: Added renderer support for accessing background image from filters X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=4d2641578cb5103e09504a763f4016f136bf1386;p=inkscape.git Added renderer support for accessing background image from filters --- diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 9657715ea..b4cc3930b 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -196,6 +196,11 @@ void nr_arena_group_set_style (NRArenaGroup *group, SPStyle *style) if (style && style->filter.set && style->filter.filter) { group->filter = new NR::Filter(); } + + if (style && style->enable_background.set + && style->enable_background.value == SP_CSS_BACKGROUND_NEW) { + group->background_new = true; + } } static unsigned int diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 57413ef22..7e03c51dd 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -97,6 +97,8 @@ nr_arena_item_init (NRArenaItem *item) item->px = NULL; item->data = NULL; item->filter = NULL; + item->background_pb = NULL; + item->background_new = false; } static void @@ -552,11 +554,21 @@ unsigned int nr_arena_item_invoke_render(NRArenaItem *item, NRRectL const *area, #endif } else { /* Determine, whether we need temporary buffer */ - if (item->clip || item->mask || ((item->opacity != 255) && !item->render_opacity && item->arena->rendermode != RENDERMODE_OUTLINE) || item->filter) { + if (item->clip || item->mask + || ((item->opacity != 255) && !item->render_opacity && item->arena->rendermode != RENDERMODE_OUTLINE) + || item->filter || item->background_new + || (item->parent && item->parent->background_pb) ) + { NRPixBlock ipb, mpb; /* Setup and render item buffer */ nr_pixblock_setup_fast (&ipb, NR_PIXBLOCK_MODE_R8G8B8A8P, carea.x0, carea.y0, carea.x1, carea.y1, TRUE); + /* If background access is used, save the pixblock address. + * This address is set to NULL at the end of this block */ + if (item->background_new + || (item->parent && item->parent->background_pb)) { + item->background_pb = &ipb; + } ipb.visible_area = pb->visible_area; state = NR_ARENA_ITEM_VIRTUAL (item, render) (item, &carea, &ipb, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { @@ -568,7 +580,7 @@ unsigned int nr_arena_item_invoke_render(NRArenaItem *item, NRRectL const *area, } ipb.empty = FALSE; - /* Run filtering test, if a filter is set for this object */ + /* Run filtering, if a filter is set for this object */ if(item->filter) { item->filter->render(item, &ipb); } @@ -656,6 +668,8 @@ unsigned int nr_arena_item_invoke_render(NRArenaItem *item, NRRectL const *area, /* Compose rendering pixblock int destination */ nr_blit_pixblock_pixblock_mask (dpb, &ipb, &mpb); nr_pixblock_release (&mpb); + /* This pointer wouldn't be valid outside this block, so clear it */ + item->background_pb = NULL; } else { /* Opacity only */ nr_blit_pixblock_pixblock_alpha (dpb, &ipb, item->opacity); @@ -920,6 +934,28 @@ nr_arena_item_set_order (NRArenaItem *item, int order) nr_arena_item_set_child_position (item->parent, item, ref); } +/** Returns a background image for use with filter effects. */ +NRPixBlock *nr_arena_item_get_background (NRArenaItem const *item, int depth) +{ + NRPixBlock *pb; + if (!item->background_pb) return NULL; + if (item->background_new) { + pb = new NRPixBlock(); + nr_pixblock_setup_fast(pb, item->background_pb->mode, + item->background_pb->area.x0, + item->background_pb->area.y0, + item->background_pb->area.x1, + item->background_pb->area.y1, true); + } else if (item->parent) { + pb = nr_arena_item_get_background(item->parent, depth + 1); + } else return NULL; + + if (depth > 0) + nr_blit_pixblock_pixblock(pb, item->background_pb); + + return pb; +} + /* Helpers */ NRArenaItem * diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h index d38e44929..52408d154 100644 --- a/src/display/nr-arena-item.h +++ b/src/display/nr-arena-item.h @@ -115,6 +115,10 @@ struct NRArenaItem : public NRObject { /* Current Transformation Matrix */ NR::Matrix ctm; + /* These hold background buffer state for filter rendering */ + NRPixBlock *background_pb; + bool background_new; + void init(NRArena *arena) { this->arena = arena; } @@ -180,6 +184,8 @@ void nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip); void nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask); void nr_arena_item_set_order (NRArenaItem *item, int order); +NRPixBlock *nr_arena_item_get_background (NRArenaItem const *item, int depth = 0); + /* Helpers */ NRArenaItem *nr_arena_item_attach (NRArenaItem *parent, NRArenaItem *child, NRArenaItem *prev, NRArenaItem *next); diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index ad94bd0da..e2edcd0b8 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -27,7 +27,7 @@ namespace NR { FilterGaussian::FilterGaussian() { - _deviation_x = _deviation_y = prefs_get_double_attribute("options.filtertest", "value", 0.0); + _deviation_x = _deviation_y = prefs_get_double_attribute("options.filtertest", "value", 1.0); } FilterPrimitive *FilterGaussian::create() @@ -142,10 +142,16 @@ int FilterGaussian::render(FilterSlot &slot, Matrix const &trans) /* in holds the input pixblock */ NRPixBlock *in = slot.get(_input); - /* If to either direction, the standard deviation is zero, a transparent - * black image should be returned */ - if (_deviation_x <= 0 || _deviation_y <= 0) { + /* If to either direction, the standard deviation is zero or + * input image is not defined, + * a transparent black image should be returned. */ + if (_deviation_x <= 0 || _deviation_y <= 0 || in == NULL) { NRPixBlock *out = new NRPixBlock; + if (in == NULL) { + // A bit guessing here, but source graphic is likely to be of + // right size + in = slot.get(NR_FILTER_SOURCEGRAPHIC); + } nr_pixblock_setup_fast(out, in->mode, in->area.x0, in->area.y0, in->area.x1, in->area.y1, true); out->empty = false; diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp index 9ea721d3b..890cb96fe 100644 --- a/src/display/nr-filter-primitive.cpp +++ b/src/display/nr-filter-primitive.cpp @@ -57,7 +57,7 @@ void FilterPrimitive::set_input(int slot) { } void FilterPrimitive::set_input(int input, int slot) { - if (slot == 0) _input = slot; + if (input == 0) _input = slot; } void FilterPrimitive::set_output(int slot) { diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index 6072e7993..3a2895ec6 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -14,15 +14,17 @@ */ #include + +#include "display/nr-arena-item.h" #include "libnr/nr-pixblock.h" #include "display/nr-filter-types.h" #include "display/nr-filter-slot.h" namespace NR { -FilterSlot::FilterSlot() +FilterSlot::FilterSlot(int slots, NRArenaItem const *item) { - _slot_count = 2; + _slot_count = ((slots > 0) ? slots : 2); _slot = new NRPixBlock*[_slot_count]; _slot_number = new int[_slot_count]; @@ -32,20 +34,8 @@ FilterSlot::FilterSlot() } _last_out = -1; -} - -FilterSlot::FilterSlot(int slots) -{ - _slot_count = slots; - _slot = new NRPixBlock*[_slot_count]; - _slot_number = new int[_slot_count]; - - for (int i = 0 ; i < _slot_count ; i++) { - _slot[i] = NULL; - _slot_number[i] = NR_FILTER_SLOT_NOT_SET; - } - _last_out = -1; + _arena_item = item; } FilterSlot::~FilterSlot() @@ -64,6 +54,40 @@ NRPixBlock *FilterSlot::get(int slot_nr) { int index = _get_index(slot_nr); assert(index >= 0); + + /* If we didn't have the specified image, but we could create it + * from the other information we have, let's do that */ + if (_slot[index] == NULL + && (slot_nr == NR_FILTER_SOURCEALPHA + || slot_nr == NR_FILTER_BACKGROUNDIMAGE + || slot_nr == NR_FILTER_BACKGROUNDALPHA + || slot_nr == NR_FILTER_FILLPAINT + || slot_nr == NR_FILTER_SOURCEPAINT)) + { + /* If needed, fetch background */ + if (slot_nr == NR_FILTER_BACKGROUNDIMAGE + || slot_nr == NR_FILTER_BACKGROUNDALPHA) + { + NRPixBlock *pb; + pb = nr_arena_item_get_background(_arena_item); + 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) { + // TODO + } + /* When a paint is needed, fetch it from arena item */ + if (slot_nr == NR_FILTER_FILLPAINT) { + // TODO + } + if (slot_nr == NR_FILTER_SOURCEPAINT) { + // TODO + } + } + assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr); return _slot[index]; } @@ -120,7 +144,7 @@ int FilterSlot::_get_index(int slot_nr) int seek = _slot_count; do { seek--; - } while (_slot[seek] == NULL); + } while (_slot[seek] == NULL && seek > 0); /* If there is no space for more slots, create more space */ if (seek == _slot_count - 1) { NRPixBlock **new_slot = new NRPixBlock*[_slot_count * 2]; @@ -130,8 +154,8 @@ int FilterSlot::_get_index(int slot_nr) new_number[i] = _slot_number[i]; } for (int i = _slot_count ; i < _slot_count * 2 ; i++) { - _slot[i] = NULL; - _slot_number[i] = NR_FILTER_SLOT_NOT_SET; + new_slot[i] = NULL; + new_number[i] = NR_FILTER_SLOT_NOT_SET; } delete[] _slot; delete[] _slot_number; diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 13ce1afe2..09190a9b0 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -16,14 +16,20 @@ #include "libnr/nr-pixblock.h" +struct NRArenaItem; + namespace NR { class FilterSlot { public: - /** Creates a new FilterSlot object, with two slots. */ - FilterSlot(); - /** Creates a new FilterSlot object, with specified amount of slots */ - FilterSlot(int slots); + /** Creates a new FilterSlot object. + * First parameter specifies the amount of slots this SilterSlot + * should reserve beforehand. If a negative number is given, + * two slots will be reserved. + * Second parameter specifies the arena item, which should be used + * for background accesses from filters. + */ + FilterSlot(int slots, NRArenaItem const *item); /** Destroys the FilterSlot object and all its contents */ ~FilterSlot(); @@ -58,7 +64,9 @@ private: int _last_out; - /** Returns the table index of given slot. If that slot dows not exist, + NRArenaItem const *_arena_item; + + /** Returns the table index of given slot. If that slot does not exist, * it is created. Table index can be used to read the correct * pixblock from _slot */ int _get_index(int slot); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index db1e9d8db..bda64c50c 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -84,7 +84,7 @@ Filter::~Filter() int Filter::render(NRArenaItem const *item, NRPixBlock *pb) { Matrix trans = *item->ctm; - FilterSlot slot(_slot_count); + FilterSlot slot(_slot_count, item); NRPixBlock *in = new NRPixBlock; // First, if filter resolution is not set to automatic, we should