1
#define __NR_FILTER_SLOT_CPP__
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.
9
* Niko Kiirala <niko@kiirala.com>
11
* Copyright (C) 2006,2007 Niko Kiirala
13
* Released under GNU GPL, read the file 'COPYING' for more information
19
#include "display/nr-arena-item.h"
20
#include "display/nr-filter-types.h"
21
#include "display/nr-filter-slot.h"
22
#include "display/nr-filter-getalpha.h"
23
#include "display/nr-filter-units.h"
24
#include "display/pixblock-scaler.h"
25
#include "display/pixblock-transform.h"
26
#include "libnr/nr-pixblock.h"
27
#include "libnr/nr-blit.h"
29
__attribute__ ((const))
30
inline static int _max4(const double a, const double b,
31
const double c, const double d) {
36
return (int)round(ret);
39
__attribute__ ((const))
40
inline static int _min4(const double a, const double b,
41
const double c, const double d) {
46
return (int)round(ret);
49
__attribute__ ((const))
50
inline static int _max2(const double a, const double b) {
57
__attribute__ ((const))
58
inline static int _min2(const double a, const double b) {
67
FilterSlot::FilterSlot(int slots, NRArenaItem const *item)
69
_slot_count = ((slots > 0) ? slots : 2);
70
_slot = new NRPixBlock*[_slot_count];
71
_slot_number = new int[_slot_count];
73
for (int i = 0 ; i < _slot_count ; i++) {
75
_slot_number[i] = NR_FILTER_SLOT_NOT_SET;
83
FilterSlot::~FilterSlot()
85
for (int i = 0 ; i < _slot_count ; i++) {
87
nr_pixblock_release(_slot[i]);
92
delete[] _slot_number;
95
NRPixBlock *FilterSlot::get(int slot_nr)
97
int index = _get_index(slot_nr);
100
/* If we didn't have the specified image, but we could create it
101
* from the other information we have, let's do that */
102
if (_slot[index] == NULL
103
&& (slot_nr == NR_FILTER_SOURCEALPHA
104
|| slot_nr == NR_FILTER_BACKGROUNDIMAGE
105
|| slot_nr == NR_FILTER_BACKGROUNDALPHA
106
|| slot_nr == NR_FILTER_FILLPAINT
107
|| slot_nr == NR_FILTER_STROKEPAINT))
109
/* If needed, fetch background */
110
if (slot_nr == NR_FILTER_BACKGROUNDIMAGE) {
112
pb = nr_arena_item_get_background(_arena_item);
115
this->set(NR_FILTER_BACKGROUNDIMAGE, pb);
117
NRPixBlock *source = this->get(NR_FILTER_SOURCEGRAPHIC);
118
pb = new NRPixBlock();
119
if (!pb) return NULL; // Allocation failed
120
nr_pixblock_setup_fast(pb, source->mode,
121
source->area.x0, source->area.y0,
122
source->area.x1, source->area.y1, true);
123
if (pb->size != NR_PIXBLOCK_SIZE_TINY && pb->data.px == NULL) {
129
this->set(NR_FILTER_BACKGROUNDIMAGE, pb);
131
} else if (slot_nr == NR_FILTER_SOURCEALPHA) {
132
/* If only a alpha channel is needed, strip it from full image */
133
NRPixBlock *src = get(NR_FILTER_SOURCEGRAPHIC);
134
NRPixBlock *sa = filter_get_alpha(src);
135
set(NR_FILTER_SOURCEALPHA, sa);
136
} else if (slot_nr == NR_FILTER_BACKGROUNDALPHA) {
137
NRPixBlock *src = get(NR_FILTER_BACKGROUNDIMAGE);
138
NRPixBlock *ba = filter_get_alpha(src);
139
set(NR_FILTER_BACKGROUNDALPHA, ba);
140
} else if (slot_nr == NR_FILTER_FILLPAINT) {
141
/* When a paint is needed, fetch it from arena item */
143
} else if (slot_nr == NR_FILTER_STROKEPAINT) {
149
_slot[index]->empty = false;
152
assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr);
156
void FilterSlot::get_final(int slot_nr, NRPixBlock *result) {
157
NRPixBlock *final_usr = get(slot_nr);
158
Matrix trans = units.get_matrix_pb2display();
160
int size = (result->area.x1 - result->area.x0)
161
* (result->area.y1 - result->area.y0)
162
* NR_PIXBLOCK_BPP(result);
163
memset(NR_PIXBLOCK_PX(result), 0, size);
165
if (fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) {
166
transform_bicubic(result, final_usr, trans);
167
} else if (fabs(trans[0] - 1) > 1e-6 || fabs(trans[3] - 1) > 1e-6) {
168
scale_bicubic(result, final_usr);
170
nr_blit_pixblock_pixblock(result, final_usr);
174
void FilterSlot::set(int slot_nr, NRPixBlock *pb)
176
/* Unnamed slot is for saving filter primitive results, when parameter
177
* 'result' is not set. Only the filter immediately after this one
178
* can access unnamed results, so we don't have to worry about overwriting
179
* previous results in filter chain. On the other hand, we may not
180
* overwrite any other image with this one, because they might be
181
* accessed later on. */
182
int index = ((slot_nr != NR_FILTER_SLOT_NOT_SET)
183
? _get_index(slot_nr)
184
: _get_index(NR_FILTER_UNNAMED_SLOT));
186
// Unnamed slot is only for NR::FilterSlot internal use.
187
assert(slot_nr != NR_FILTER_UNNAMED_SLOT);
188
assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr);
190
if (slot_nr == NR_FILTER_SOURCEGRAPHIC || slot_nr == NR_FILTER_BACKGROUNDIMAGE) {
191
Matrix trans = units.get_matrix_display2pb();
192
if (fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) {
193
NRPixBlock *trans_pb = new NRPixBlock;
194
int x0 = pb->area.x0;
195
int y0 = pb->area.y0;
196
int x1 = pb->area.x1;
197
int y1 = pb->area.y1;
198
int min_x = _min4(trans[0] * x0 + trans[2] * y0 + trans[4],
199
trans[0] * x0 + trans[2] * y1 + trans[4],
200
trans[0] * x1 + trans[2] * y0 + trans[4],
201
trans[0] * x1 + trans[2] * y1 + trans[4]);
202
int max_x = _max4(trans[0] * x0 + trans[2] * y0 + trans[4],
203
trans[0] * x0 + trans[2] * y1 + trans[4],
204
trans[0] * x1 + trans[2] * y0 + trans[4],
205
trans[0] * x1 + trans[2] * y1 + trans[4]);
206
int min_y = _min4(trans[1] * x0 + trans[3] * y0 + trans[5],
207
trans[1] * x0 + trans[3] * y1 + trans[5],
208
trans[1] * x1 + trans[3] * y0 + trans[5],
209
trans[1] * x1 + trans[3] * y1 + trans[5]);
210
int max_y = _max4(trans[1] * x0 + trans[3] * y0 + trans[5],
211
trans[1] * x0 + trans[3] * y1 + trans[5],
212
trans[1] * x1 + trans[3] * y0 + trans[5],
213
trans[1] * x1 + trans[3] * y1 + trans[5]);
215
nr_pixblock_setup_fast(trans_pb, pb->mode,
218
if (trans_pb->size != NR_PIXBLOCK_SIZE_TINY && trans_pb->data.px == NULL) {
219
/* TODO: this gets hit occasionally. Worst case scenario:
220
* images are exported in horizontal stripes. One stripe
221
* is not too high, but can get thousands of pixels wide.
222
* Rotate this 45 degrees -> _huge_ image */
223
g_warning("Memory allocation failed in NR::FilterSlot::set (transform)");
226
transform_bicubic(trans_pb, pb, trans);
227
nr_pixblock_release(pb);
230
} else if (fabs(trans[0] - 1) > 1e-6 || fabs(trans[3] - 1) > 1e-6) {
231
NRPixBlock *trans_pb = new NRPixBlock;
233
int x0 = pb->area.x0;
234
int y0 = pb->area.y0;
235
int x1 = pb->area.x1;
236
int y1 = pb->area.y1;
237
int min_x = _min2(trans[0] * x0 + trans[4],
238
trans[0] * x1 + trans[4]);
239
int max_x = _max2(trans[0] * x0 + trans[4],
240
trans[0] * x1 + trans[4]);
241
int min_y = _min2(trans[3] * y0 + trans[5],
242
trans[3] * y1 + trans[5]);
243
int max_y = _max2(trans[3] * y0 + trans[5],
244
trans[3] * y1 + trans[5]);
246
nr_pixblock_setup_fast(trans_pb, pb->mode,
247
min_x, min_y, max_x, max_y, true);
248
if (trans_pb->size != NR_PIXBLOCK_SIZE_TINY && trans_pb->data.px == NULL) {
249
g_warning("Memory allocation failed in NR::FilterSlot::set (scaling)");
252
scale_bicubic(trans_pb, pb);
253
nr_pixblock_release(pb);
260
nr_pixblock_release(_slot[index]);
267
int FilterSlot::get_slot_count()
269
int seek = _slot_count;
272
} while (!_slot[seek] && _slot_number[seek] == NR_FILTER_SLOT_NOT_SET);
277
NRArenaItem const* FilterSlot::get_arenaitem()
282
int FilterSlot::_get_index(int slot_nr)
284
assert(slot_nr >= 0 ||
285
slot_nr == NR_FILTER_SLOT_NOT_SET ||
286
slot_nr == NR_FILTER_SOURCEGRAPHIC ||
287
slot_nr == NR_FILTER_SOURCEALPHA ||
288
slot_nr == NR_FILTER_BACKGROUNDIMAGE ||
289
slot_nr == NR_FILTER_BACKGROUNDALPHA ||
290
slot_nr == NR_FILTER_FILLPAINT ||
291
slot_nr == NR_FILTER_STROKEPAINT ||
292
slot_nr == NR_FILTER_UNNAMED_SLOT);
295
if (slot_nr == NR_FILTER_SLOT_NOT_SET) {
298
/* Search, if the slot already exists */
299
for (int i = 0 ; i < _slot_count ; i++) {
300
if (_slot_number[i] == slot_nr) {
306
/* If the slot doesn't already exist, create it */
308
int seek = _slot_count;
311
} while (_slot_number[seek] == NR_FILTER_SLOT_NOT_SET && seek >= 0);
312
/* If there is no space for more slots, create more space */
313
if (seek == _slot_count - 1) {
314
NRPixBlock **new_slot = new NRPixBlock*[_slot_count * 2];
315
int *new_number = new int[_slot_count * 2];
316
for (int i = 0 ; i < _slot_count ; i++) {
317
new_slot[i] = _slot[i];
318
new_number[i] = _slot_number[i];
320
for (int i = _slot_count ; i < _slot_count * 2 ; i++) {
322
new_number[i] = NR_FILTER_SLOT_NOT_SET;
325
delete[] _slot_number;
327
_slot_number = new_number;
330
/* Now that there is space, create the slot */
331
_slot_number[seek + 1] = slot_nr;
337
void FilterSlot::set_units(FilterUnits const &units) {
346
c-file-style:"stroustrup"
347
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
352
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :