~ubuntu-branches/debian/experimental/inkscape/experimental

« back to all changes in this revision

Viewing changes to src/display/nr-filter-slot.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-09-09 23:29:02 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20080909232902-c50iujhk1w79u8e7
Tags: 0.46-2.1
* Non-maintainer upload.
* Add upstream patch fixing a crash in the open dialog
  in the zh_CN.utf8 locale. Closes: #487623.
  Thanks to Luca Bruno for the patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define __NR_FILTER_SLOT_CPP__
 
2
 
 
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,2007 Niko Kiirala
 
12
 *
 
13
 * Released under GNU GPL, read the file 'COPYING' for more information
 
14
 */
 
15
 
 
16
#include <assert.h>
 
17
#include <string.h>
 
18
 
 
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"
 
28
 
 
29
__attribute__ ((const))
 
30
inline static int _max4(const double a, const double b,
 
31
                        const double c, const double d) {
 
32
    double ret = a;
 
33
    if (b > ret) ret = b;
 
34
    if (c > ret) ret = c;
 
35
    if (d > ret) ret = d;
 
36
    return (int)round(ret);
 
37
}
 
38
 
 
39
__attribute__ ((const))
 
40
inline static int _min4(const double a, const double b,
 
41
                        const double c, const double d) {
 
42
    double ret = a;
 
43
    if (b < ret) ret = b;
 
44
    if (c < ret) ret = c;
 
45
    if (d < ret) ret = d;
 
46
    return (int)round(ret);
 
47
}
 
48
 
 
49
__attribute__ ((const))
 
50
inline static int _max2(const double a, const double b) {
 
51
    if (a > b)
 
52
        return (int)round(a);
 
53
    else
 
54
        return (int)round(b);
 
55
}
 
56
 
 
57
__attribute__ ((const))
 
58
inline static int _min2(const double a, const double b) {
 
59
    if (a > b)
 
60
        return (int)round(b);
 
61
    else
 
62
        return (int)round(a);
 
63
}
 
64
 
 
65
namespace NR {
 
66
 
 
67
FilterSlot::FilterSlot(int slots, NRArenaItem const *item)
 
68
{
 
69
    _slot_count = ((slots > 0) ? slots : 2);
 
70
    _slot = new NRPixBlock*[_slot_count];
 
71
    _slot_number = new int[_slot_count];
 
72
 
 
73
    for (int i = 0 ; i < _slot_count ; i++) {
 
74
        _slot[i] = NULL;
 
75
        _slot_number[i] = NR_FILTER_SLOT_NOT_SET;
 
76
    }
 
77
 
 
78
    _last_out = -1;
 
79
 
 
80
    _arena_item = item;
 
81
}
 
82
 
 
83
FilterSlot::~FilterSlot()
 
84
{
 
85
    for (int i = 0 ; i < _slot_count ; i++) {
 
86
        if (_slot[i]) {
 
87
            nr_pixblock_release(_slot[i]);
 
88
            delete _slot[i];
 
89
        }
 
90
    }
 
91
    delete[] _slot;
 
92
    delete[] _slot_number;
 
93
}
 
94
 
 
95
NRPixBlock *FilterSlot::get(int slot_nr)
 
96
{
 
97
    int index = _get_index(slot_nr);
 
98
    assert(index >= 0);
 
99
 
 
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))
 
108
    {
 
109
        /* If needed, fetch background */
 
110
        if (slot_nr == NR_FILTER_BACKGROUNDIMAGE) {
 
111
            NRPixBlock *pb;
 
112
            pb = nr_arena_item_get_background(_arena_item);
 
113
            if (pb) {
 
114
                pb->empty = false;
 
115
                this->set(NR_FILTER_BACKGROUNDIMAGE, pb);
 
116
            } else {
 
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) {
 
124
                    // allocation failed
 
125
                    delete pb;
 
126
                    return NULL;
 
127
                }
 
128
                pb->empty = FALSE;
 
129
                this->set(NR_FILTER_BACKGROUNDIMAGE, pb);
 
130
            }
 
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 */
 
142
            // TODO
 
143
        } else if (slot_nr == NR_FILTER_STROKEPAINT) {
 
144
            // TODO
 
145
        }
 
146
    }
 
147
 
 
148
    if (_slot[index]) {
 
149
        _slot[index]->empty = false;
 
150
    }
 
151
 
 
152
    assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr);
 
153
    return _slot[index];
 
154
}
 
155
 
 
156
void FilterSlot::get_final(int slot_nr, NRPixBlock *result) {
 
157
    NRPixBlock *final_usr = get(slot_nr);
 
158
    Matrix trans = units.get_matrix_pb2display();
 
159
 
 
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);
 
164
 
 
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);
 
169
    } else {
 
170
        nr_blit_pixblock_pixblock(result, final_usr);
 
171
    }
 
172
}
 
173
 
 
174
void FilterSlot::set(int slot_nr, NRPixBlock *pb)
 
175
{
 
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));
 
185
    assert(index >= 0);
 
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);
 
189
 
 
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]);
 
214
            
 
215
            nr_pixblock_setup_fast(trans_pb, pb->mode,
 
216
                                   min_x, min_y,
 
217
                                   max_x, max_y, true);
 
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)");
 
224
                return;
 
225
            }
 
226
            transform_bicubic(trans_pb, pb, trans);
 
227
            nr_pixblock_release(pb);
 
228
            delete pb;
 
229
            pb = trans_pb;
 
230
        } else if (fabs(trans[0] - 1) > 1e-6 || fabs(trans[3] - 1) > 1e-6) {
 
231
            NRPixBlock *trans_pb = new NRPixBlock;
 
232
 
 
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]);
 
245
 
 
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)");
 
250
                return;
 
251
            }
 
252
            scale_bicubic(trans_pb, pb);
 
253
            nr_pixblock_release(pb);
 
254
            delete pb;
 
255
            pb = trans_pb;
 
256
        }
 
257
    }
 
258
 
 
259
    if(_slot[index]) {
 
260
        nr_pixblock_release(_slot[index]);
 
261
        delete _slot[index];
 
262
    }
 
263
    _slot[index] = pb;
 
264
    _last_out = index;
 
265
}
 
266
 
 
267
int FilterSlot::get_slot_count()
 
268
{
 
269
    int seek = _slot_count;
 
270
    do {
 
271
        seek--;
 
272
    } while (!_slot[seek] && _slot_number[seek] == NR_FILTER_SLOT_NOT_SET);
 
273
 
 
274
    return seek + 1;
 
275
}
 
276
 
 
277
NRArenaItem const* FilterSlot::get_arenaitem()
 
278
{
 
279
        return _arena_item;
 
280
}
 
281
 
 
282
int FilterSlot::_get_index(int slot_nr)
 
283
{
 
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);
 
293
 
 
294
    int index = -1;
 
295
    if (slot_nr == NR_FILTER_SLOT_NOT_SET) {
 
296
        return _last_out;
 
297
    }
 
298
    /* Search, if the slot already exists */
 
299
    for (int i = 0 ; i < _slot_count ; i++) {
 
300
        if (_slot_number[i] == slot_nr) {
 
301
            index = i;
 
302
            break;
 
303
        }
 
304
    }
 
305
 
 
306
    /* If the slot doesn't already exist, create it */
 
307
    if (index == -1) {
 
308
        int seek = _slot_count;
 
309
        do {
 
310
            seek--;
 
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];
 
319
            }
 
320
            for (int i = _slot_count ; i < _slot_count * 2 ; i++) {
 
321
                new_slot[i] = NULL;
 
322
                new_number[i] = NR_FILTER_SLOT_NOT_SET;
 
323
            }
 
324
            delete[] _slot;
 
325
            delete[] _slot_number;
 
326
            _slot = new_slot;
 
327
            _slot_number = new_number;
 
328
            _slot_count *= 2;
 
329
        }
 
330
        /* Now that there is space, create the slot */
 
331
        _slot_number[seek + 1] = slot_nr;
 
332
        index = seek + 1;
 
333
    }
 
334
    return index;
 
335
}
 
336
 
 
337
void FilterSlot::set_units(FilterUnits const &units) {
 
338
    this->units = units;
 
339
}
 
340
 
 
341
}
 
342
 
 
343
/*
 
344
  Local Variables:
 
345
  mode:c++
 
346
  c-file-style:"stroustrup"
 
347
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
348
  indent-tabs-mode:nil
 
349
  fill-column:99
 
350
  End:
 
351
*/
 
352
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :