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];
110 }
112 void FilterSlot::set(int slot_nr, NRPixBlock *pb)
113 {
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;
124 }
126 int FilterSlot::get_slot_count()
127 {
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;
134 }
136 NRArenaItem const* FilterSlot::get_arenaitem()
137 {
138 return _arena_item;
139 }
141 int FilterSlot::_get_index(int slot_nr)
142 {
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;
193 }
195 }
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 :