Code

added some more boilerplate code on feTurbulence.
[inkscape.git] / src / display / nr-filter-slot.cpp
1 #define __NR_FILTER_SLOT_CPP__
3 /*
4  * A container class for filter slots. Allows for simple getting and
5  * setting images in filter slots without having to bother with
6  * table indexes and such.
7  *
8  * Author:
9  *   Niko Kiirala <niko@kiirala.com>
10  *
11  * Copyright (C) 2006 Niko Kiirala
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 #include <assert.h>
18 #include "display/nr-arena-item.h"
19 #include "display/nr-filter-types.h"
20 #include "display/nr-filter-slot.h"
21 #include "display/nr-filter-getalpha.h"
22 #include "libnr/nr-pixblock.h"
23 #include "libnr/nr-blit.h"
25 namespace NR {
27 FilterSlot::FilterSlot(int slots, NRArenaItem const *item)
28 {
29     _slot_count = ((slots > 0) ? slots : 2);
30     _slot = new NRPixBlock*[_slot_count];
31     _slot_number = new int[_slot_count];
33     for (int i = 0 ; i < _slot_count ; i++) {
34         _slot[i] = NULL;
35         _slot_number[i] = NR_FILTER_SLOT_NOT_SET;
36     }
38     _last_out = -1;
40     _arena_item = item;
41 }
43 FilterSlot::~FilterSlot()
44 {
45     for (int i = 0 ; i < _slot_count ; i++) {
46         if (_slot[i]) {
47             nr_pixblock_release(_slot[i]);
48             delete _slot[i];
49         }
50     }
51     delete[] _slot;
52     delete[] _slot_number;
53 }
55 NRPixBlock *FilterSlot::get(int slot_nr)
56 {
57     int index = _get_index(slot_nr);
58     assert(index >= 0);
60     /* If we didn't have the specified image, but we could create it
61      * from the other information we have, let's do that */
62     if (_slot[index] == NULL
63         && (slot_nr == NR_FILTER_SOURCEALPHA
64             || slot_nr == NR_FILTER_BACKGROUNDIMAGE
65             || slot_nr == NR_FILTER_BACKGROUNDALPHA
66             || slot_nr == NR_FILTER_FILLPAINT
67             || slot_nr == NR_FILTER_STROKEPAINT))
68     {
69         /* If needed, fetch background */
70         if (slot_nr == NR_FILTER_BACKGROUNDIMAGE) {
71             NRPixBlock *pb;
72             pb = nr_arena_item_get_background(_arena_item);
73             if (pb) {
74                 pb->empty = false;
75                 this->set(NR_FILTER_BACKGROUNDIMAGE, pb);
76             } else {
77                 NRPixBlock *source = this->get(NR_FILTER_SOURCEGRAPHIC);
78                 pb = new NRPixBlock();
79                 if (!pb) return NULL; // Allocation failed
80                 nr_pixblock_setup_fast(pb, source->mode,
81                                        source->area.x0, source->area.y0,
82                                        source->area.x1, source->area.y1, true);
83                 if (pb->size != NR_PIXBLOCK_SIZE_TINY && pb->data.px == NULL) {
84                     // allocation failed
85                     delete pb;
86                     return NULL;
87                 }
88                 pb->empty = FALSE;
89                 this->set(NR_FILTER_BACKGROUNDIMAGE, pb);
90             }
91         } else if (slot_nr == NR_FILTER_SOURCEALPHA) {
92             /* If only a alpha channel is needed, strip it from full image */
93             NRPixBlock *src = get(NR_FILTER_SOURCEGRAPHIC);
94             NRPixBlock *sa = filter_get_alpha(src);
95             set(NR_FILTER_SOURCEALPHA, sa);
96         } else if (slot_nr == NR_FILTER_BACKGROUNDALPHA) {
97             NRPixBlock *src = get(NR_FILTER_BACKGROUNDIMAGE);
98             NRPixBlock *ba = filter_get_alpha(src);
99             set(NR_FILTER_BACKGROUNDALPHA, ba);
100         } else if (slot_nr == NR_FILTER_FILLPAINT) {
101             /* When a paint is needed, fetch it from arena item */
102             // TODO
103         } else if (slot_nr == NR_FILTER_STROKEPAINT) {
104             // TODO
105         }
106     }
108     assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr);
109     return _slot[index];
112 void FilterSlot::set(int slot_nr, NRPixBlock *pb)
114     int index = _get_index(slot_nr);
115     assert(index >= 0);
116     assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr);
118     if(_slot[index]) {
119         nr_pixblock_release(_slot[index]);
120         delete _slot[index];
121     }
122     _slot[index] = pb;
123     _last_out = index;
126 int FilterSlot::get_slot_count()
128     int seek = _slot_count;
129     do {
130         seek--;
131     } while (!_slot[seek] && _slot_number[seek] == NR_FILTER_SLOT_NOT_SET);
133     return seek + 1;
136 NRArenaItem const* FilterSlot::get_arenaitem()
138         return _arena_item;
141 int FilterSlot::_get_index(int slot_nr)
143     assert(slot_nr >= 0 ||
144            slot_nr == NR_FILTER_SLOT_NOT_SET ||
145            slot_nr == NR_FILTER_SOURCEGRAPHIC ||
146            slot_nr == NR_FILTER_SOURCEALPHA ||
147            slot_nr == NR_FILTER_BACKGROUNDIMAGE ||
148            slot_nr == NR_FILTER_BACKGROUNDALPHA ||
149            slot_nr == NR_FILTER_FILLPAINT ||
150            slot_nr == NR_FILTER_STROKEPAINT);
152     int index = -1;
153     if (slot_nr == NR_FILTER_SLOT_NOT_SET) {
154         return _last_out;
155     }
156     /* Search, if the slot already exists */
157     for (int i = 0 ; i < _slot_count ; i++) {
158         if (_slot_number[i] == slot_nr) {
159             index = i;
160             break;
161         }
162     }
164     /* If the slot doesn't already exist, create it */
165     if (index == -1) {
166         int seek = _slot_count;
167         do {
168             seek--;
169         } while (_slot_number[seek] == NR_FILTER_SLOT_NOT_SET && seek >= 0);
170         /* If there is no space for more slots, create more space */
171         if (seek == _slot_count - 1) {
172             NRPixBlock **new_slot = new NRPixBlock*[_slot_count * 2];
173             int *new_number = new int[_slot_count * 2];
174             for (int i = 0 ; i < _slot_count ; i++) {
175                 new_slot[i] = _slot[i];
176                 new_number[i] = _slot_number[i];
177             }
178             for (int i = _slot_count ; i < _slot_count * 2 ; i++) {
179                 new_slot[i] = NULL;
180                 new_number[i] = NR_FILTER_SLOT_NOT_SET;
181             }
182             delete[] _slot;
183             delete[] _slot_number;
184             _slot = new_slot;
185             _slot_number = new_number;
186             _slot_count *= 2;
187         }
188         /* Now that there is space, create the slot */
189         _slot_number[seek + 1] = slot_nr;
190         index = seek + 1;
191     }
192     return index;
197 /*
198   Local Variables:
199   mode:c++
200   c-file-style:"stroustrup"
201   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
202   indent-tabs-mode:nil
203   fill-column:99
204   End:
205 */
206 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :