~centralelyon2010/inkscape/imagelinks2

6885 by Ted Gould
From trunk
1
/** @file
2
 * @brief Bucket fill drawing context, works by bitmap filling an area on a rendered version
3
 * of the current display and then tracing the result using potrace.
4
 */
5
/* Author:
6
 *   Lauris Kaplinski <lauris@kaplinski.com>
7
 *   bulia byak <buliabyak@users.sf.net>
8
 *   John Bintz <jcoswell@coswellproductions.org>
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
9
 *   Jon A. Cruz <jon@joncruz.org>
10
 *   Abhishek Sharma
6885 by Ted Gould
From trunk
11
 *
12
 * Copyright (C) 2006      Johan Engelen <johan@shouraizou.nl>
13
 * Copyright (C) 2000-2005 authors
14
 * Copyright (C) 2000-2001 Ximian, Inc.
15
 *
16
 * Released under GNU GPL, read the file 'COPYING' for more information
17
 */
2432 by johncoswell
Add flood fill tool
18
6885 by Ted Gould
From trunk
19
#ifdef HAVE_CONFIG_H
2432 by johncoswell
Add flood fill tool
20
#include "config.h"
6885 by Ted Gould
From trunk
21
#endif
2432 by johncoswell
Add flood fill tool
22
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
23
#include <2geom/pathvector.h>
2432 by johncoswell
Add flood fill tool
24
#include <gdk/gdkkeysyms.h>
25
#include <queue>
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
26
#include <deque>
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
27
#include <glibmm/i18n.h>
2432 by johncoswell
Add flood fill tool
28
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
29
#include "color.h"
30
#include "context-fns.h"
31
#include "desktop.h"
32
#include "desktop-handles.h"
33
#include "desktop-style.h"
34
#include "display/cairo-utils.h"
35
#include "display/drawing-context.h"
36
#include "display/drawing-image.h"
37
#include "display/drawing-item.h"
38
#include "display/drawing.h"
2432 by johncoswell
Add flood fill tool
39
#include "display/sp-canvas.h"
40
#include "document.h"
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
41
#include "flood-context.h"
42
#include "livarot/Path.h"
43
#include "livarot/Shape.h"
44
#include "macros.h"
45
#include "message-context.h"
2538 by mental
adapt code to new Maybe/bbox regime
46
#include "message-stack.h"
2432 by johncoswell
Add flood fill tool
47
#include "object-edit.h"
6885 by Ted Gould
From trunk
48
#include "preferences.h"
2900 by johncoswell
Add ability to drag cursor while holding alt to add multiple points to paint bucket action
49
#include "rubberband.h"
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
50
#include "selection.h"
7097 by buliabyak
switch to using shape_editor, instead of separate knotholders and listeners; fixes a lot of crashes, simplifies code
51
#include "shape-editor.h"
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
52
#include "sp-defs.h"
2432 by johncoswell
Add flood fill tool
53
#include "sp-item.h"
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
54
#include "splivarot.h"
55
#include "sp-metrics.h"
56
#include "sp-namedview.h"
57
#include "sp-object.h"
58
#include "sp-path.h"
59
#include "sp-rect.h"
2432 by johncoswell
Add flood fill tool
60
#include "sp-root.h"
61
#include "svg/svg.h"
5466 by johncoswell
Have Paint Bucket generate the necessary GrayMap for potrace directly, skipping the standard, slower potrace filtering routines.
62
#include "trace/imagemap.h"
2432 by johncoswell
Add flood fill tool
63
#include "trace/potrace/inkscape-potrace.h"
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
64
#include "trace/trace.h"
65
#include "xml/node-event-vector.h"
66
#include "xml/repr.h"
67
68
#include "pixmaps/cursor-paintbucket.xpm"
69
70
using Inkscape::DocumentUndo;
2432 by johncoswell
Add flood fill tool
71
72
static void sp_flood_context_class_init(SPFloodContextClass *klass);
73
static void sp_flood_context_init(SPFloodContext *flood_context);
74
static void sp_flood_context_dispose(GObject *object);
75
76
static void sp_flood_context_setup(SPEventContext *ec);
77
78
static gint sp_flood_context_root_handler(SPEventContext *event_context, GdkEvent *event);
79
static gint sp_flood_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event);
80
81
static void sp_flood_finish(SPFloodContext *rc);
82
83
static SPEventContextClass *parent_class;
84
85
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
86
GType sp_flood_context_get_type()
2432 by johncoswell
Add flood fill tool
87
{
88
    static GType type = 0;
89
    if (!type) {
90
        GTypeInfo info = {
91
            sizeof(SPFloodContextClass),
92
            NULL, NULL,
93
            (GClassInitFunc) sp_flood_context_class_init,
94
            NULL, NULL,
95
            sizeof(SPFloodContext),
96
            4,
97
            (GInstanceInitFunc) sp_flood_context_init,
98
            NULL,    /* value_table */
99
        };
100
        type = g_type_register_static(SP_TYPE_EVENT_CONTEXT, "SPFloodContext", &info, (GTypeFlags) 0);
101
    }
102
    return type;
103
}
104
105
static void sp_flood_context_class_init(SPFloodContextClass *klass)
106
{
107
    GObjectClass *object_class = (GObjectClass *) klass;
108
    SPEventContextClass *event_context_class = (SPEventContextClass *) klass;
109
110
    parent_class = (SPEventContextClass *) g_type_class_peek_parent(klass);
111
112
    object_class->dispose = sp_flood_context_dispose;
113
114
    event_context_class->setup = sp_flood_context_setup;
115
    event_context_class->root_handler  = sp_flood_context_root_handler;
116
    event_context_class->item_handler  = sp_flood_context_item_handler;
117
}
118
119
static void sp_flood_context_init(SPFloodContext *flood_context)
120
{
121
    SPEventContext *event_context = SP_EVENT_CONTEXT(flood_context);
122
2538 by mental
adapt code to new Maybe/bbox regime
123
    event_context->cursor_shape = cursor_paintbucket_xpm;
124
    event_context->hot_x = 11;
125
    event_context->hot_y = 30;
2432 by johncoswell
Add flood fill tool
126
    event_context->xp = 0;
127
    event_context->yp = 0;
2931 by johncoswell
Improve fill dragging by increasing drag tolerance and preventing already-filled pixels from being checked in gradient fills
128
    event_context->tolerance = 4;
2432 by johncoswell
Add flood fill tool
129
    event_context->within_tolerance = false;
130
    event_context->item_to_select = NULL;
131
132
    flood_context->item = NULL;
133
134
    new (&flood_context->sel_changed_connection) sigc::connection();
135
}
136
137
static void sp_flood_context_dispose(GObject *object)
138
{
139
    SPFloodContext *rc = SP_FLOOD_CONTEXT(object);
140
    SPEventContext *ec = SP_EVENT_CONTEXT(object);
141
142
    rc->sel_changed_connection.disconnect();
143
    rc->sel_changed_connection.~connection();
144
7097 by buliabyak
switch to using shape_editor, instead of separate knotholders and listeners; fixes a lot of crashes, simplifies code
145
    delete ec->shape_editor;
146
    ec->shape_editor = NULL;
147
2432 by johncoswell
Add flood fill tool
148
    /* fixme: This is necessary because we do not grab */
149
    if (rc->item) {
150
        sp_flood_finish(rc);
151
    }
152
153
    if (rc->_message_context) {
154
        delete rc->_message_context;
155
    }
156
157
    G_OBJECT_CLASS(parent_class)->dispose(object);
158
}
159
160
/**
161
\brief  Callback that processes the "changed" signal on the selection;
162
destroys old and creates new knotholder
163
*/
164
void sp_flood_context_selection_changed(Inkscape::Selection *selection, gpointer data)
165
{
166
    SPFloodContext *rc = SP_FLOOD_CONTEXT(data);
167
    SPEventContext *ec = SP_EVENT_CONTEXT(rc);
168
7097 by buliabyak
switch to using shape_editor, instead of separate knotholders and listeners; fixes a lot of crashes, simplifies code
169
    ec->shape_editor->unset_item(SH_KNOTHOLDER);
170
    SPItem *item = selection->singleItem(); 
171
    ec->shape_editor->set_item(item, SH_KNOTHOLDER);
2432 by johncoswell
Add flood fill tool
172
}
173
174
static void sp_flood_context_setup(SPEventContext *ec)
175
{
176
    SPFloodContext *rc = SP_FLOOD_CONTEXT(ec);
177
178
    if (((SPEventContextClass *) parent_class)->setup) {
179
        ((SPEventContextClass *) parent_class)->setup(ec);
180
    }
181
7097 by buliabyak
switch to using shape_editor, instead of separate knotholders and listeners; fixes a lot of crashes, simplifies code
182
    ec->shape_editor = new ShapeEditor(ec->desktop);
183
2432 by johncoswell
Add flood fill tool
184
    SPItem *item = sp_desktop_selection(ec->desktop)->singleItem();
185
    if (item) {
7097 by buliabyak
switch to using shape_editor, instead of separate knotholders and listeners; fixes a lot of crashes, simplifies code
186
        ec->shape_editor->set_item(item, SH_KNOTHOLDER);
2432 by johncoswell
Add flood fill tool
187
    }
188
189
    rc->sel_changed_connection.disconnect();
190
    rc->sel_changed_connection = sp_desktop_selection(ec->desktop)->connectChanged(
191
        sigc::bind(sigc::ptr_fun(&sp_flood_context_selection_changed), (gpointer)rc)
192
    );
193
194
    rc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack());
4457 by cilix42
Add missing selection cue option to preferences for tweak, calligraphy, and paint bucket tools
195
6885 by Ted Gould
From trunk
196
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
197
    if (prefs->getBool("/tools/paintbucket/selcue")) {
4457 by cilix42
Add missing selection cue option to preferences for tweak, calligraphy, and paint bucket tools
198
        rc->enableSelectionCue();
199
    }
2432 by johncoswell
Add flood fill tool
200
}
201
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
202
inline static guint32
203
compose_onto (guint32 px, guint32 bg)
2639 by johncoswell
Clean up indentation
204
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
205
    EXTRACT_ARGB32(px, ap,rp,gp,bp)
206
    EXTRACT_ARGB32(bg, ab,rb,gb,bb)
207
    guint32 ao,ro,bo,go;
208
209
    ao = 255*255 - (255-ap)*(255-bp);  ao = (ao + 127) / 255;
210
    ro = (255-ap)*rb + rp;             ro = (ro + 127) / 255;
211
    go = (255-ap)*gb + gp;             go = (go + 127) / 255;
212
    bo = (255-ap)*bb + bp;             bo = (bo + 127) / 255;
213
214
    ASSEMBLE_ARGB32(pxout, ao,ro,go,bo)
215
    return pxout;
2561 by johncoswell
Begin work on selectable color channels for paint bucket, starting with visible colors and alpha
216
}
217
5096 by johncoswell
Add doxygen comments to flood-context.cpp
218
/**
219
 * \brief Get the pointer to a pixel in a pixel buffer.
220
 * \param px The pixel buffer.
221
 * \param x The X coordinate.
222
 * \param y The Y coordinate.
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
223
 * \param stride The rowstride of the pixel buffer.
5096 by johncoswell
Add doxygen comments to flood-context.cpp
224
 */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
225
inline guint32 get_pixel(guchar *px, int x, int y, int stride) {
226
    return *reinterpret_cast<guint32*>(px + y * stride + x * 4);
2432 by johncoswell
Add flood fill tool
227
}
228
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
229
inline unsigned char * get_trace_pixel(guchar *trace_px, int x, int y, int width) {
230
    return trace_px + (x + y * width);
231
}
232
5096 by johncoswell
Add doxygen comments to flood-context.cpp
233
/**
234
 * \brief Generate the list of trace channel selection entries.
235
 */
2561 by johncoswell
Begin work on selectable color channels for paint bucket, starting with visible colors and alpha
236
GList * flood_channels_dropdown_items_list() {
237
    GList *glist = NULL;
238
239
    glist = g_list_append (glist, _("Visible Colors"));
2571 by johncoswell
Add and adjust fill channels
240
    glist = g_list_append (glist, _("Red"));
241
    glist = g_list_append (glist, _("Green"));
242
    glist = g_list_append (glist, _("Blue"));
2579 by johncoswell
Add HSL options to paint bucket channels
243
    glist = g_list_append (glist, _("Hue"));
244
    glist = g_list_append (glist, _("Saturation"));
245
    glist = g_list_append (glist, _("Lightness"));
2561 by johncoswell
Begin work on selectable color channels for paint bucket, starting with visible colors and alpha
246
    glist = g_list_append (glist, _("Alpha"));
247
248
    return glist;
249
}
250
5096 by johncoswell
Add doxygen comments to flood-context.cpp
251
/**
252
 * \brief Generate the list of autogap selection entries.
253
 */
3040 by johncoswell
Add auto gap filling for Paint Bucket and implement "safety valve" to prevent runaway fill operations
254
GList * flood_autogap_dropdown_items_list() {
255
    GList *glist = NULL;
256
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
257
    glist = g_list_append (glist, (void*) C_("Flood autogap", "None"));
258
    glist = g_list_append (glist, (void*) C_("Flood autogap", "Small"));
259
    glist = g_list_append (glist, (void*) C_("Flood autogap", "Medium"));
260
    glist = g_list_append (glist, (void*) C_("Flood autogap", "Large"));
3040 by johncoswell
Add auto gap filling for Paint Bucket and implement "safety valve" to prevent runaway fill operations
261
262
    return glist;
263
}
264
5096 by johncoswell
Add doxygen comments to flood-context.cpp
265
/**
266
 * \brief Compare a pixel in a pixel buffer with another pixel to determine if a point should be included in the fill operation.
267
 * \param check The pixel in the pixel buffer to check.
268
 * \param orig The original selected pixel to use as the fill target color.
269
 * \param merged_orig_pixel The original pixel merged with the background.
270
 * \param dtc The desktop background color.
271
 * \param threshold The fill threshold.
272
 * \param method The fill method to use as defined in PaintBucketChannels.
273
 */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
274
static bool compare_pixels(guint32 check, guint32 orig, guint32 merged_orig_pixel, guint32 dtc, int threshold, PaintBucketChannels method)
275
{
2639 by johncoswell
Clean up indentation
276
    int diff = 0;
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
277
    float hsl_check[3] = {0,0,0}, hsl_orig[3] = {0,0,0};
278
279
    EXTRACT_ARGB32(check, ac,rc,gc,bc)
280
    EXTRACT_ARGB32(orig, ao,ro,go,bo)
281
    EXTRACT_ARGB32(dtc, ad,rd,gd,bd)
282
    EXTRACT_ARGB32(merged_orig_pixel, amop,rmop,gmop,bmop)
283
2639 by johncoswell
Clean up indentation
284
    if ((method == FLOOD_CHANNELS_H) ||
285
        (method == FLOOD_CHANNELS_S) ||
286
        (method == FLOOD_CHANNELS_L)) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
287
        double dac = ac;
288
        double dao = ao;
289
        sp_color_rgb_to_hsl_floatv(hsl_check, rc / dac, gc / dac, bc / dac);
290
        sp_color_rgb_to_hsl_floatv(hsl_orig, ro / dao, go / dao, bo / dao);
2639 by johncoswell
Clean up indentation
291
    }
292
    
293
    switch (method) {
294
        case FLOOD_CHANNELS_ALPHA:
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
295
            return abs(static_cast<int>(ac) - ao) <= threshold;
2639 by johncoswell
Clean up indentation
296
        case FLOOD_CHANNELS_R:
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
297
            return abs(static_cast<int>(ac ? unpremul_alpha(rc, ac) : 0) - (ao ? unpremul_alpha(ro, ao) : 0)) <= threshold;
2639 by johncoswell
Clean up indentation
298
        case FLOOD_CHANNELS_G:
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
299
            return abs(static_cast<int>(ac ? unpremul_alpha(gc, ac) : 0) - (ao ? unpremul_alpha(go, ao) : 0)) <= threshold;
2639 by johncoswell
Clean up indentation
300
        case FLOOD_CHANNELS_B:
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
301
            return abs(static_cast<int>(ac ? unpremul_alpha(bc, ac) : 0) - (ao ? unpremul_alpha(bo, ao) : 0)) <= threshold;
2639 by johncoswell
Clean up indentation
302
        case FLOOD_CHANNELS_RGB:
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
303
            guint32 amc, rmc, bmc, gmc;
304
            amc = 255*255 - (255-ac)*(255-ad); amc = (amc + 127) / 255;
305
            rmc = (255-ac)*rd + rc; rmc = (rmc + 127) / 255;
306
            gmc = (255-ac)*gd + gc; gmc = (gmc + 127) / 255;
307
            bmc = (255-ac)*bd + bc; bmc = (bmc + 127) / 255;
308
309
            diff += abs(static_cast<int>(amc ? unpremul_alpha(rmc, amc) : 0) - (amop ? unpremul_alpha(rmop, amop) : 0));
310
            diff += abs(static_cast<int>(amc ? unpremul_alpha(gmc, amc) : 0) - (amop ? unpremul_alpha(gmop, amop) : 0));
311
            diff += abs(static_cast<int>(amc ? unpremul_alpha(bmc, amc) : 0) - (amop ? unpremul_alpha(bmop, amop) : 0));
2639 by johncoswell
Clean up indentation
312
            return ((diff / 3) <= ((threshold * 3) / 4));
313
        
314
        case FLOOD_CHANNELS_H:
315
            return ((int)(fabs(hsl_check[0] - hsl_orig[0]) * 100.0) <= threshold);
316
        case FLOOD_CHANNELS_S:
317
            return ((int)(fabs(hsl_check[1] - hsl_orig[1]) * 100.0) <= threshold);
318
        case FLOOD_CHANNELS_L:
319
            return ((int)(fabs(hsl_check[2] - hsl_orig[2]) * 100.0) <= threshold);
320
    }
321
    
322
    return false;
2538 by mental
adapt code to new Maybe/bbox regime
323
}
324
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
325
enum {
326
  PIXEL_CHECKED = 1,
327
  PIXEL_QUEUED  = 2,
328
  PIXEL_PAINTABLE = 4,
329
  PIXEL_NOT_PAINTABLE = 8,
330
  PIXEL_COLORED = 16
331
};
332
333
static inline bool is_pixel_checked(unsigned char *t) { return (*t & PIXEL_CHECKED) == PIXEL_CHECKED; }
334
static inline bool is_pixel_queued(unsigned char *t) { return (*t & PIXEL_QUEUED) == PIXEL_QUEUED; }
335
static inline bool is_pixel_paintability_checked(unsigned char *t) {
336
  return !((*t & PIXEL_PAINTABLE) == 0) && ((*t & PIXEL_NOT_PAINTABLE) == 0);
337
}
338
static inline bool is_pixel_paintable(unsigned char *t) { return (*t & PIXEL_PAINTABLE) == PIXEL_PAINTABLE; }
339
static inline bool is_pixel_colored(unsigned char *t) { return (*t & PIXEL_COLORED) == PIXEL_COLORED; }
340
341
static inline void mark_pixel_checked(unsigned char *t) { *t |= PIXEL_CHECKED; }
342
static inline void mark_pixel_unchecked(unsigned char *t) { *t ^= PIXEL_CHECKED; }
343
static inline void mark_pixel_queued(unsigned char *t) { *t |= PIXEL_QUEUED; }
344
static inline void mark_pixel_paintable(unsigned char *t) { *t |= PIXEL_PAINTABLE; *t ^= PIXEL_NOT_PAINTABLE; }
345
static inline void mark_pixel_not_paintable(unsigned char *t) { *t |= PIXEL_NOT_PAINTABLE; *t ^= PIXEL_PAINTABLE; }
346
static inline void mark_pixel_colored(unsigned char *t) { *t |= PIXEL_COLORED; }
347
348
static inline void clear_pixel_paintability(unsigned char *t) { *t ^= PIXEL_PAINTABLE; *t ^= PIXEL_NOT_PAINTABLE; }
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
349
350
struct bitmap_coords_info {
351
    bool is_left;
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
352
    unsigned int x;
353
    unsigned int y;
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
354
    int y_limit;
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
355
    unsigned int width;
356
    unsigned int height;
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
357
    unsigned int stride;
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
358
    unsigned int threshold;
359
    unsigned int radius;
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
360
    PaintBucketChannels method;
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
361
    guint32 dtc;
362
    guint32 merged_orig_pixel;
6839 by cilix42
Next roud of NR ==> Geom conversion
363
    Geom::Rect bbox;
364
    Geom::Rect screen;
3046 by johncoswell
Add optimizations for Paint Bucket bitmap fill
365
    unsigned int max_queue_size;
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
366
    unsigned int current_step;
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
367
};
368
5096 by johncoswell
Add doxygen comments to flood-context.cpp
369
/**
370
 * \brief Check if a pixel can be included in the fill.
371
 * \param px The rendered pixel buffer to check.
372
 * \param trace_t The pixel in the trace pixel buffer to check or mark.
373
 * \param x The X coordinate.
374
 * \param y The y coordinate.
375
 * \param orig_color The original selected pixel to use as the fill target color.
376
 * \param bci The bitmap_coords_info structure.
377
 */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
378
inline static bool check_if_pixel_is_paintable(guchar *px, unsigned char *trace_t, int x, int y, guint32 orig_color, bitmap_coords_info bci) {
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
379
    if (is_pixel_paintability_checked(trace_t)) {
380
        return is_pixel_paintable(trace_t);
381
    } else {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
382
        guint32 pixel = get_pixel(px, x, y, bci.stride);
383
        if (compare_pixels(pixel, orig_color, bci.merged_orig_pixel, bci.dtc, bci.threshold, bci.method)) {
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
384
            mark_pixel_paintable(trace_t);
385
            return true;
386
        } else {
387
            mark_pixel_not_paintable(trace_t);
388
            return false;
389
        }
390
    }
391
}
392
5096 by johncoswell
Add doxygen comments to flood-context.cpp
393
/**
394
 * \brief Perform the bitmap-to-vector tracing and place the traced path onto the document.
395
 * \param px The trace pixel buffer to trace to SVG.
396
 * \param desktop The desktop on which to place the final SVG path.
397
 * \param transform The transform to apply to the final SVG path.
398
 * \param union_with_selection If true, merge the final SVG path with the current selection.
399
 */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
400
static void do_trace(bitmap_coords_info bci, guchar *trace_px, SPDesktop *desktop, Geom::Affine transform, unsigned int min_x, unsigned int max_x, unsigned int min_y, unsigned int max_y, bool union_with_selection) {
8422 by cilix42
Revert recent refactoring changes by johnce because they break the build, which cannot be fixed easily.
401
    SPDocument *document = sp_desktop_document(desktop);
5466 by johncoswell
Have Paint Bucket generate the necessary GrayMap for potrace directly, skipping the standard, slower potrace filtering routines.
402
403
    unsigned char *trace_t;
404
5479 by johncoswell
Only trace the painted area of the screen with each fill, reducing memory usage.
405
    GrayMap *gray_map = GrayMapCreate((max_x - min_x + 1), (max_y - min_y + 1));
406
    unsigned int gray_map_y = 0;
407
    for (unsigned int y = min_y; y <= max_y; y++) {
408
        unsigned long *gray_map_t = gray_map->rows[gray_map_y];
5467 by johncoswell
Small Paint Bucket optimization for creating GrayMap
409
5479 by johncoswell
Only trace the painted area of the screen with each fill, reducing memory usage.
410
        trace_t = get_trace_pixel(trace_px, min_x, y, bci.width);
411
        for (unsigned int x = min_x; x <= max_x; x++) {
5467 by johncoswell
Small Paint Bucket optimization for creating GrayMap
412
            *gray_map_t = is_pixel_colored(trace_t) ? GRAYMAP_BLACK : GRAYMAP_WHITE;
413
            gray_map_t++;
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
414
            trace_t++;
5466 by johncoswell
Have Paint Bucket generate the necessary GrayMap for potrace directly, skipping the standard, slower potrace filtering routines.
415
        }
5479 by johncoswell
Only trace the painted area of the screen with each fill, reducing memory usage.
416
        gray_map_y++;
5466 by johncoswell
Have Paint Bucket generate the necessary GrayMap for potrace directly, skipping the standard, slower potrace filtering routines.
417
    }
418
2432 by johncoswell
Add flood fill tool
419
    Inkscape::Trace::Potrace::PotraceTracingEngine pte;
6885 by Ted Gould
From trunk
420
    pte.keepGoing = 1;
5466 by johncoswell
Have Paint Bucket generate the necessary GrayMap for potrace directly, skipping the standard, slower potrace filtering routines.
421
    std::vector<Inkscape::Trace::TracingEngineResult> results = pte.traceGrayMap(gray_map);
422
    gray_map->destroy(gray_map);
2432 by johncoswell
Add flood fill tool
423
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
424
    //XML Tree being used here directly while it shouldn't be...."
425
    Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
2432 by johncoswell
Add flood fill tool
426
427
    long totalNodeCount = 0L;
428
6885 by Ted Gould
From trunk
429
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
430
    double offset = prefs->getDouble("/tools/paintbucket/offset", 0.0);
2538 by mental
adapt code to new Maybe/bbox regime
431
2432 by johncoswell
Add flood fill tool
432
    for (unsigned int i=0 ; i<results.size() ; i++) {
433
        Inkscape::Trace::TracingEngineResult result = results[i];
434
        totalNodeCount += result.getNodeCount();
435
436
        Inkscape::XML::Node *pathRepr = xml_doc->createElement("svg:path");
437
        /* Set style */
6885 by Ted Gould
From trunk
438
        sp_desktop_apply_style_tool (desktop, pathRepr, "/tools/paintbucket", false);
2432 by johncoswell
Add flood fill tool
439
6215 by johanengelen
2geomify conversion to livaror in flood-context.cpp
440
        Geom::PathVector pathv = sp_svg_read_pathv(result.getPathData().c_str());
441
        Path *path = new Path;
442
        path->LoadPathVector(pathv);
2568 by buliabyak
do not offset if offset==0; display messages if success and if no path created because of too much inset
443
444
        if (offset != 0) {
445
        
446
            Shape *path_shape = new Shape();
447
        
448
            path->ConvertWithBackData(0.03);
449
            path->Fill(path_shape, 0);
450
            delete path;
451
        
452
            Shape *expanded_path_shape = new Shape();
453
        
454
            expanded_path_shape->ConvertToShape(path_shape, fill_nonZero);
455
            path_shape->MakeOffset(expanded_path_shape, offset * desktop->current_zoom(), join_round, 4);
456
            expanded_path_shape->ConvertToShape(path_shape, fill_positive);
457
458
            Path *expanded_path = new Path();
459
        
460
            expanded_path->Reset();
461
            expanded_path_shape->ConvertToForme(expanded_path);
462
            expanded_path->ConvertEvenLines(1.0);
463
            expanded_path->Simplify(1.0);
464
        
465
            delete path_shape;
466
            delete expanded_path_shape;
467
        
468
            gchar *str = expanded_path->svg_dump_path();
469
            if (str && *str) {
470
                pathRepr->setAttribute("d", str);
471
                g_free(str);
472
            } else {
473
                desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("<b>Too much inset</b>, the result is empty."));
474
                Inkscape::GC::release(pathRepr);
475
                g_free(str);
476
                return;
477
            }
478
479
            delete expanded_path;
480
481
        } else {
482
            gchar *str = path->svg_dump_path();
483
            delete path;
484
            pathRepr->setAttribute("d", str);
485
            g_free(str);
486
        }
2538 by mental
adapt code to new Maybe/bbox regime
487
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
488
        desktop->currentLayer()->addChild(pathRepr,NULL);
2432 by johncoswell
Add flood fill tool
489
490
        SPObject *reprobj = document->getObjectByRepr(pathRepr);
491
        if (reprobj) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
492
            SP_ITEM(reprobj)->doWriteTransform(pathRepr, transform, NULL);
2538 by mental
adapt code to new Maybe/bbox regime
493
            
494
            // premultiply the item transform by the accumulated parent transform in the paste layer
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
495
            Geom::Affine local (SP_GROUP(desktop->currentLayer())->i2doc_affine());
6839 by cilix42
Next roud of NR ==> Geom conversion
496
            if (!local.isIdentity()) {
2538 by mental
adapt code to new Maybe/bbox regime
497
                gchar const *t_str = pathRepr->attribute("transform");
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
498
                Geom::Affine item_t (Geom::identity());
2538 by mental
adapt code to new Maybe/bbox regime
499
                if (t_str)
500
                    sp_svg_transform_read(t_str, &item_t);
501
                item_t *= local.inverse();
502
                // (we're dealing with unattached repr, so we write to its attr instead of using sp_item_set_transform)
503
                gchar *affinestr=sp_svg_transform_write(item_t);
504
                pathRepr->setAttribute("transform", affinestr);
505
                g_free(affinestr);
506
            }
507
2432 by johncoswell
Add flood fill tool
508
            Inkscape::Selection *selection = sp_desktop_selection(desktop);
2792 by johncoswell
Change paint bucket path union to properly create only one undo event, rather than two
509
2435 by johncoswell
Add ability to flood fill areas of contiguous color
510
            pathRepr->setPosition(-1);
2568 by buliabyak
do not offset if offset==0; display messages if success and if no path created because of too much inset
511
2792 by johncoswell
Change paint bucket path union to properly create only one undo event, rather than two
512
            if (union_with_selection) {
4719 by prokoudine
i18n patch from Marcin
513
                desktop->messageStack()->flashF(Inkscape::WARNING_MESSAGE, ngettext("Area filled, path with <b>%d</b> node created and unioned with selection.","Area filled, path with <b>%d</b> nodes created and unioned with selection.",sp_nodes_in_path(SP_PATH(reprobj))), sp_nodes_in_path(SP_PATH(reprobj)));
2792 by johncoswell
Change paint bucket path union to properly create only one undo event, rather than two
514
                selection->add(reprobj);
6633 by cilix42
Eliminate more of SP_ACTIVE_DESKTOP
515
                sp_selected_path_union_skip_undo(desktop);
2792 by johncoswell
Change paint bucket path union to properly create only one undo event, rather than two
516
            } else {
4719 by prokoudine
i18n patch from Marcin
517
                desktop->messageStack()->flashF(Inkscape::WARNING_MESSAGE, ngettext("Area filled, path with <b>%d</b> node created.","Area filled, path with <b>%d</b> nodes created.",sp_nodes_in_path(SP_PATH(reprobj))), sp_nodes_in_path(SP_PATH(reprobj)));
2792 by johncoswell
Change paint bucket path union to properly create only one undo event, rather than two
518
                selection->set(reprobj);
519
            }
520
2432 by johncoswell
Add flood fill tool
521
        }
2792 by johncoswell
Change paint bucket path union to properly create only one undo event, rather than two
522
2432 by johncoswell
Add flood fill tool
523
        Inkscape::GC::release(pathRepr);
2568 by buliabyak
do not offset if offset==0; display messages if success and if no path created because of too much inset
524
2432 by johncoswell
Add flood fill tool
525
    }
526
}
527
5096 by johncoswell
Add doxygen comments to flood-context.cpp
528
/**
529
 * \brief The possible return states of perform_bitmap_scanline_check()
530
 */
2538 by mental
adapt code to new Maybe/bbox regime
531
enum ScanlineCheckResult {
2639 by johncoswell
Clean up indentation
532
    SCANLINE_CHECK_OK,
533
    SCANLINE_CHECK_ABORTED,
534
    SCANLINE_CHECK_BOUNDARY
2538 by mental
adapt code to new Maybe/bbox regime
535
};
536
5096 by johncoswell
Add doxygen comments to flood-context.cpp
537
/**
538
 * \brief Determine if the provided coordinates are within the pixel buffer limits.
539
 * \param x The X coordinate.
540
 * \param y The Y coordinate.
541
 * \param bci The bitmap_coords_info structure.
542
 */
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
543
inline static bool coords_in_range(unsigned int x, unsigned int y, bitmap_coords_info bci) {
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
544
    return (x < bci.width) &&
545
           (y < bci.height);
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
546
}
547
548
#define PAINT_DIRECTION_LEFT 1
549
#define PAINT_DIRECTION_RIGHT 2
550
#define PAINT_DIRECTION_UP 4
551
#define PAINT_DIRECTION_DOWN 8
3046 by johncoswell
Add optimizations for Paint Bucket bitmap fill
552
#define PAINT_DIRECTION_ALL 15
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
553
5096 by johncoswell
Add doxygen comments to flood-context.cpp
554
/**
555
 * \brief Paint a pixel or a square (if autogap is enabled) on the trace pixel buffer
556
 * \param px The rendered pixel buffer to check.
557
 * \param trace_px The trace pixel buffer.
558
 * \param orig_color The original selected pixel to use as the fill target color.
559
 * \param bci The bitmap_coords_info structure.
560
 * \param original_point_trace_t The original pixel in the trace pixel buffer to check.
561
 */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
562
inline static unsigned int paint_pixel(guchar *px, guchar *trace_px, guint32 orig_color, bitmap_coords_info bci, unsigned char *original_point_trace_t) {
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
563
    if (bci.radius == 0) {
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
564
        mark_pixel_colored(original_point_trace_t); 
3046 by johncoswell
Add optimizations for Paint Bucket bitmap fill
565
        return PAINT_DIRECTION_ALL;
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
566
    } else {
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
567
        unsigned char *trace_t;
568
  
3046 by johncoswell
Add optimizations for Paint Bucket bitmap fill
569
        bool can_paint_up = true;
570
        bool can_paint_down = true;
571
        bool can_paint_left = true;
572
        bool can_paint_right = true;
573
      
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
574
        for (unsigned int ty = bci.y - bci.radius; ty <= bci.y + bci.radius; ty++) {
575
            for (unsigned int tx = bci.x - bci.radius; tx <= bci.x + bci.radius; tx++) {
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
576
                if (coords_in_range(tx, ty, bci)) {
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
577
                    trace_t = get_trace_pixel(trace_px, tx, ty, bci.width);
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
578
                    if (!is_pixel_colored(trace_t)) {
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
579
                        if (check_if_pixel_is_paintable(px, trace_t, tx, ty, orig_color, bci)) {
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
580
                            mark_pixel_colored(trace_t); 
581
                        } else {
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
582
                            if (tx < bci.x) { can_paint_left = false; }
583
                            if (tx > bci.x) { can_paint_right = false; }
584
                            if (ty < bci.y) { can_paint_up = false; }
585
                            if (ty > bci.y) { can_paint_down = false; }
3040 by johncoswell
Add auto gap filling for Paint Bucket and implement "safety valve" to prevent runaway fill operations
586
                        }
587
                    }
588
                }
589
            }
590
        }
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
591
    
592
        unsigned int paint_directions = 0;
593
        if (can_paint_left) { paint_directions += PAINT_DIRECTION_LEFT; }
594
        if (can_paint_right) { paint_directions += PAINT_DIRECTION_RIGHT; }
595
        if (can_paint_up) { paint_directions += PAINT_DIRECTION_UP; }
596
        if (can_paint_down) { paint_directions += PAINT_DIRECTION_DOWN; }
597
        
598
        return paint_directions;
3040 by johncoswell
Add auto gap filling for Paint Bucket and implement "safety valve" to prevent runaway fill operations
599
    }
600
}
601
5096 by johncoswell
Add doxygen comments to flood-context.cpp
602
/**
603
 * \brief Push a point to be checked onto the bottom of the rendered pixel buffer check queue.
604
 * \param fill_queue The fill queue to add the point to.
605
 * \param max_queue_size The maximum size of the fill queue.
606
 * \param trace_t The trace pixel buffer pixel.
607
 * \param x The X coordinate.
608
 * \param y The Y coordinate.
609
 */
6839 by cilix42
Next roud of NR ==> Geom conversion
610
static void push_point_onto_queue(std::deque<Geom::Point> *fill_queue, unsigned int max_queue_size, unsigned char *trace_t, unsigned int x, unsigned int y) {
3447 by johncoswell
Include new routines for building the fill point queue in a standard way
611
    if (!is_pixel_queued(trace_t)) {
612
        if ((fill_queue->size() < max_queue_size)) {
6839 by cilix42
Next roud of NR ==> Geom conversion
613
            fill_queue->push_back(Geom::Point(x, y));
3447 by johncoswell
Include new routines for building the fill point queue in a standard way
614
            mark_pixel_queued(trace_t);
615
        }
616
    }
617
}
618
5096 by johncoswell
Add doxygen comments to flood-context.cpp
619
/**
620
 * \brief Shift a point to be checked onto the top of the rendered pixel buffer check queue.
621
 * \param fill_queue The fill queue to add the point to.
622
 * \param max_queue_size The maximum size of the fill queue.
623
 * \param trace_t The trace pixel buffer pixel.
624
 * \param x The X coordinate.
625
 * \param y The Y coordinate.
626
 */
6839 by cilix42
Next roud of NR ==> Geom conversion
627
static void shift_point_onto_queue(std::deque<Geom::Point> *fill_queue, unsigned int max_queue_size, unsigned char *trace_t, unsigned int x, unsigned int y) {
3447 by johncoswell
Include new routines for building the fill point queue in a standard way
628
    if (!is_pixel_queued(trace_t)) {
629
        if ((fill_queue->size() < max_queue_size)) {
6839 by cilix42
Next roud of NR ==> Geom conversion
630
            fill_queue->push_front(Geom::Point(x, y));
3447 by johncoswell
Include new routines for building the fill point queue in a standard way
631
            mark_pixel_queued(trace_t);
632
        }
633
    }
634
}
635
5096 by johncoswell
Add doxygen comments to flood-context.cpp
636
/**
637
 * \brief Scan a row in the rendered pixel buffer and add points to the fill queue as necessary.
638
 * \param fill_queue The fill queue to add the point to.
639
 * \param px The rendered pixel buffer.
640
 * \param trace_px The trace pixel buffer.
641
 * \param orig_color The original selected pixel to use as the fill target color.
642
 * \param bci The bitmap_coords_info structure.
643
 */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
644
static ScanlineCheckResult perform_bitmap_scanline_check(std::deque<Geom::Point> *fill_queue, guchar *px, guchar *trace_px, guint32 orig_color, bitmap_coords_info bci, unsigned int *min_x, unsigned int *max_x) {
2538 by mental
adapt code to new Maybe/bbox regime
645
    bool aborted = false;
646
    bool reached_screen_boundary = false;
647
    bool ok;
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
648
2538 by mental
adapt code to new Maybe/bbox regime
649
    bool keep_tracing;
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
650
    bool initial_paint = true;
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
651
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
652
    unsigned char *current_trace_t = get_trace_pixel(trace_px, bci.x, bci.y, bci.width);
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
653
    unsigned int paint_directions;
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
654
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
655
    bool currently_painting_top = false;
656
    bool currently_painting_bottom = false;
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
657
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
658
    unsigned int top_ty = bci.y - 1;
659
    unsigned int bottom_ty = bci.y + 1;
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
660
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
661
    bool can_paint_top = (top_ty > 0);
662
    bool can_paint_bottom = (bottom_ty < bci.height);
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
663
6839 by cilix42
Next roud of NR ==> Geom conversion
664
    Geom::Point t = fill_queue->front();
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
665
2538 by mental
adapt code to new Maybe/bbox regime
666
    do {
667
        ok = false;
668
        if (bci.is_left) {
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
669
            keep_tracing = (bci.x != 0);
2538 by mental
adapt code to new Maybe/bbox regime
670
        } else {
671
            keep_tracing = (bci.x < bci.width);
672
        }
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
673
5479 by johncoswell
Only trace the painted area of the screen with each fill, reducing memory usage.
674
        *min_x = MIN(*min_x, bci.x);
675
        *max_x = MAX(*max_x, bci.x);
676
2538 by mental
adapt code to new Maybe/bbox regime
677
        if (keep_tracing) {
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
678
            if (check_if_pixel_is_paintable(px, current_trace_t, bci.x, bci.y, orig_color, bci)) {
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
679
                paint_directions = paint_pixel(px, trace_px, orig_color, bci, current_trace_t);
680
                if (bci.radius == 0) {
681
                    mark_pixel_checked(current_trace_t);
6839 by cilix42
Next roud of NR ==> Geom conversion
682
                    if ((t[Geom::X] == bci.x) && (t[Geom::Y] == bci.y)) {
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
683
                        fill_queue->pop_front(); t = fill_queue->front();
684
                    }
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
685
                }
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
686
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
687
                if (can_paint_top) {
688
                    if (paint_directions & PAINT_DIRECTION_UP) { 
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
689
                        unsigned char *trace_t = current_trace_t - bci.width;
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
690
                        if (!is_pixel_queued(trace_t)) {
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
691
                            bool ok_to_paint = check_if_pixel_is_paintable(px, trace_t, bci.x, top_ty, orig_color, bci);
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
692
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
693
                            if (initial_paint) { currently_painting_top = !ok_to_paint; }
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
694
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
695
                            if (ok_to_paint && (!currently_painting_top)) {
696
                                currently_painting_top = true;
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
697
                                push_point_onto_queue(fill_queue, bci.max_queue_size, trace_t, bci.x, top_ty);
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
698
                            }
699
                            if ((!ok_to_paint) && currently_painting_top) {
700
                                currently_painting_top = false;
701
                            }
702
                        }
703
                    }
704
                }
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
705
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
706
                if (can_paint_bottom) {
707
                    if (paint_directions & PAINT_DIRECTION_DOWN) { 
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
708
                        unsigned char *trace_t = current_trace_t + bci.width;
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
709
                        if (!is_pixel_queued(trace_t)) {
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
710
                            bool ok_to_paint = check_if_pixel_is_paintable(px, trace_t, bci.x, bottom_ty, orig_color, bci);
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
711
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
712
                            if (initial_paint) { currently_painting_bottom = !ok_to_paint; }
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
713
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
714
                            if (ok_to_paint && (!currently_painting_bottom)) {
715
                                currently_painting_bottom = true;
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
716
                                push_point_onto_queue(fill_queue, bci.max_queue_size, trace_t, bci.x, bottom_ty);
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
717
                            }
718
                            if ((!ok_to_paint) && currently_painting_bottom) {
719
                                currently_painting_bottom = false;
720
                            }
721
                        }
722
                    }
3047 by johncoswell
Add fillaccuracy preference
723
                }
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
724
2538 by mental
adapt code to new Maybe/bbox regime
725
                if (bci.is_left) {
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
726
                    if (paint_directions & PAINT_DIRECTION_LEFT) {
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
727
                        bci.x--; current_trace_t--;
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
728
                        ok = true;
729
                    }
2538 by mental
adapt code to new Maybe/bbox regime
730
                } else {
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
731
                    if (paint_directions & PAINT_DIRECTION_RIGHT) {
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
732
                        bci.x++; current_trace_t++;
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
733
                        ok = true;
734
                    }
2538 by mental
adapt code to new Maybe/bbox regime
735
                }
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
736
3049 by johncoswell
Finish Paint Bucket optimizations & fixes for auto gap
737
                initial_paint = false;
2538 by mental
adapt code to new Maybe/bbox regime
738
            }
739
        } else {
6839 by cilix42
Next roud of NR ==> Geom conversion
740
            if (bci.bbox.min()[Geom::X] > bci.screen.min()[Geom::X]) {
2538 by mental
adapt code to new Maybe/bbox regime
741
                aborted = true; break;
742
            } else {
743
                reached_screen_boundary = true;
744
            }
745
        }
746
    } while (ok);
4079 by johncoswell
change pixel queuing method & add pixel queue cleanup routine to reduce number of function calls for each fill peration
747
2538 by mental
adapt code to new Maybe/bbox regime
748
    if (aborted) { return SCANLINE_CHECK_ABORTED; }
749
    if (reached_screen_boundary) { return SCANLINE_CHECK_BOUNDARY; }
750
    return SCANLINE_CHECK_OK;
751
}
752
5096 by johncoswell
Add doxygen comments to flood-context.cpp
753
/**
754
 * \brief Sort the rendered pixel buffer check queue vertically.
755
 */
6839 by cilix42
Next roud of NR ==> Geom conversion
756
static bool sort_fill_queue_vertical(Geom::Point a, Geom::Point b) {
757
    return a[Geom::Y] > b[Geom::Y];
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
758
}
759
5096 by johncoswell
Add doxygen comments to flood-context.cpp
760
/**
761
 * \brief Sort the rendered pixel buffer check queue horizontally.
762
 */
6839 by cilix42
Next roud of NR ==> Geom conversion
763
static bool sort_fill_queue_horizontal(Geom::Point a, Geom::Point b) {
764
    return a[Geom::X] > b[Geom::X];
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
765
}
766
5096 by johncoswell
Add doxygen comments to flood-context.cpp
767
/**
768
 * \brief Perform a flood fill operation.
769
 * \param event_context The event context for this tool.
770
 * \param event The details of this event.
771
 * \param union_with_selection If true, union the new fill with the current selection.
772
 * \param is_point_fill If false, use the Rubberband "touch selection" to get the initial points for the fill.
773
 * \param is_touch_fill If true, use only the initial contact point in the Rubberband "touch selection" as the fill target color.
774
 */
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
775
static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *event, bool union_with_selection, bool is_point_fill, bool is_touch_fill) {
2432 by johncoswell
Add flood fill tool
776
    SPDesktop *desktop = event_context->desktop;
8422 by cilix42
Revert recent refactoring changes by johnce because they break the build, which cannot be fixed easily.
777
    SPDocument *document = sp_desktop_document(desktop);
2432 by johncoswell
Add flood fill tool
778
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
779
    document->ensureUpToDate();
2432 by johncoswell
Add flood fill tool
780
    
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
781
    Geom::OptRect bbox = document->getRoot()->visualBounds();
2538 by mental
adapt code to new Maybe/bbox regime
782
783
    if (!bbox) {
2639 by johncoswell
Clean up indentation
784
        desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("<b>Area is not bounded</b>, cannot fill."));
785
        return;
2538 by mental
adapt code to new Maybe/bbox regime
786
    }
787
    
788
    double zoom_scale = desktop->current_zoom();
5096 by johncoswell
Add doxygen comments to flood-context.cpp
789
    
790
    // Render 160% of the physical display to the render pixel buffer, so that available
791
    // fill areas off the screen can be included in the fill.
2538 by mental
adapt code to new Maybe/bbox regime
792
    double padding = 1.6;
793
6839 by cilix42
Next roud of NR ==> Geom conversion
794
    Geom::Rect screen = desktop->get_display_area();
795
796
    unsigned int width = (int)ceil(screen.width() * zoom_scale * padding);
797
    unsigned int height = (int)ceil(screen.height() * zoom_scale * padding);
798
799
    Geom::Point origin(screen.min()[Geom::X],
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
800
                       document->getHeight() - screen.height() - screen.min()[Geom::Y]);
2639 by johncoswell
Clean up indentation
801
                    
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
802
    origin[Geom::X] += (screen.width() * ((1 - padding) / 2));
803
    origin[Geom::Y] += (screen.height() * ((1 - padding) / 2));
2538 by mental
adapt code to new Maybe/bbox regime
804
    
6839 by cilix42
Next roud of NR ==> Geom conversion
805
    Geom::Scale scale(zoom_scale, zoom_scale);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
806
    Geom::Affine affine = scale * Geom::Translate(-origin * scale);
807
808
    int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
809
    guchar *px = g_new(guchar, stride * height);
810
    guint32 bgcolor, dtc;
811
812
    { // this block limits the lifetime of Drawing and DrawingContext
813
        /* Create DrawingItems and set transform */
814
        unsigned dkey = SPItem::display_key_new(1);
815
        Inkscape::Drawing drawing;
816
        Inkscape::DrawingItem *root = document->getRoot()->invoke_show( drawing, dkey, SP_ITEM_SHOW_DISPLAY);
817
        root->setTransform(affine);
818
        drawing.setRoot(root);
819
820
        Geom::IntRect final_bbox = Geom::IntRect::from_xywh(0, 0, width, height);
821
        drawing.update(final_bbox);
822
823
        cairo_surface_t *s = cairo_image_surface_create_for_data(
824
            px, CAIRO_FORMAT_ARGB32, width, height, stride);
825
        Inkscape::DrawingContext ct(s, Geom::Point(0,0));
826
        // cairo_translate not necessary here - surface origin is at 0,0
827
828
        SPNamedView *nv = sp_desktop_namedview(desktop);
829
        bgcolor = nv->pagecolor;
830
        // bgcolor is 0xrrggbbaa, we need 0xaarrggbb
831
        dtc = (bgcolor >> 8) | (bgcolor << 24);
832
833
        ct.setSource(bgcolor);
834
        ct.setOperator(CAIRO_OPERATOR_SOURCE);
835
        ct.paint();
836
        ct.setOperator(CAIRO_OPERATOR_OVER);
837
838
        drawing.render(ct, final_bbox);
839
840
        cairo_surface_flush(s);
841
        cairo_surface_destroy(s);
842
        
843
        // Hide items
844
        document->getRoot()->invoke_hide(dkey);
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
845
    }
2561 by johncoswell
Begin work on selectable color channels for paint bucket, starting with visible colors and alpha
846
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
847
    guchar *trace_px = g_new(guchar, width * height);
848
    memset(trace_px, 0x00, width * height);
2538 by mental
adapt code to new Maybe/bbox regime
849
    
6839 by cilix42
Next roud of NR ==> Geom conversion
850
    std::deque<Geom::Point> fill_queue;
851
    std::queue<Geom::Point> color_queue;
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
852
    
6839 by cilix42
Next roud of NR ==> Geom conversion
853
    std::vector<Geom::Point> fill_points;
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
854
    
2900 by johncoswell
Add ability to drag cursor while holding alt to add multiple points to paint bucket action
855
    bool aborted = false;
856
    int y_limit = height - 1;
2435 by johncoswell
Add ability to flood fill areas of contiguous color
857
6885 by Ted Gould
From trunk
858
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
859
    PaintBucketChannels method = (PaintBucketChannels) prefs->getInt("/tools/paintbucket/channels", 0);
860
    int threshold = prefs->getIntLimited("/tools/paintbucket/threshold", 1, 0, 100);
2579 by johncoswell
Add HSL options to paint bucket channels
861
862
    switch(method) {
2639 by johncoswell
Clean up indentation
863
        case FLOOD_CHANNELS_ALPHA:
864
        case FLOOD_CHANNELS_RGB:
865
        case FLOOD_CHANNELS_R:
866
        case FLOOD_CHANNELS_G:
867
        case FLOOD_CHANNELS_B:
868
            threshold = (255 * threshold) / 100;
869
            break;
870
        case FLOOD_CHANNELS_H:
871
        case FLOOD_CHANNELS_S:
872
        case FLOOD_CHANNELS_L:
873
            break;
3447 by johncoswell
Include new routines for building the fill point queue in a standard way
874
    }
2538 by mental
adapt code to new Maybe/bbox regime
875
876
    bitmap_coords_info bci;
877
    
878
    bci.y_limit = y_limit;
879
    bci.width = width;
3040 by johncoswell
Add auto gap filling for Paint Bucket and implement "safety valve" to prevent runaway fill operations
880
    bci.height = height;
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
881
    bci.stride = stride;
2597 by johncoswell
Change tolerance to threshold
882
    bci.threshold = threshold;
2561 by johncoswell
Begin work on selectable color channels for paint bucket, starting with visible colors and alpha
883
    bci.method = method;
2538 by mental
adapt code to new Maybe/bbox regime
884
    bci.bbox = *bbox;
885
    bci.screen = screen;
2561 by johncoswell
Begin work on selectable color channels for paint bucket, starting with visible colors and alpha
886
    bci.dtc = dtc;
6885 by Ted Gould
From trunk
887
    bci.radius = prefs->getIntLimited("/tools/paintbucket/autogap", 0, 0, 3);
3448 by johncoswell
Tweak max queue size.
888
    bci.max_queue_size = (width * height) / 4;
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
889
    bci.current_step = 0;
3040 by johncoswell
Add auto gap filling for Paint Bucket and implement "safety valve" to prevent runaway fill operations
890
3447 by johncoswell
Include new routines for building the fill point queue in a standard way
891
    if (is_point_fill) {
6839 by cilix42
Next roud of NR ==> Geom conversion
892
        fill_points.push_back(Geom::Point(event->button.x, event->button.y));
3447 by johncoswell
Include new routines for building the fill point queue in a standard way
893
    } else {
9012.1.255 by Josh Andler
Patch by Daniel_J for 522327
894
        Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
3447 by johncoswell
Include new routines for building the fill point queue in a standard way
895
        fill_points = r->getPoints();
896
    }
897
898
    for (unsigned int i = 0; i < fill_points.size(); i++) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
899
        Geom::Point pw = Geom::Point(fill_points[i][Geom::X] / zoom_scale, document->getHeight() + (fill_points[i][Geom::Y] / zoom_scale)) * affine;
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
900
6839 by cilix42
Next roud of NR ==> Geom conversion
901
        pw[Geom::X] = (int)MIN(width - 1, MAX(0, pw[Geom::X]));
902
        pw[Geom::Y] = (int)MIN(height - 1, MAX(0, pw[Geom::Y]));
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
903
3447 by johncoswell
Include new routines for building the fill point queue in a standard way
904
        if (is_touch_fill) {
905
            if (i == 0) {
906
                color_queue.push(pw);
907
            } else {
6839 by cilix42
Next roud of NR ==> Geom conversion
908
                unsigned char *trace_t = get_trace_pixel(trace_px, (int)pw[Geom::X], (int)pw[Geom::Y], width);
909
                push_point_onto_queue(&fill_queue, bci.max_queue_size, trace_t, (int)pw[Geom::X], (int)pw[Geom::Y]);
3447 by johncoswell
Include new routines for building the fill point queue in a standard way
910
            }
911
        } else {
912
            color_queue.push(pw);
913
        }
914
    }
915
916
    bool reached_screen_boundary = false;
917
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
918
    bool first_run = true;
2538 by mental
adapt code to new Maybe/bbox regime
919
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
920
    unsigned long sort_size_threshold = 5;
921
5479 by johncoswell
Only trace the painted area of the screen with each fill, reducing memory usage.
922
    unsigned int min_y = height;
923
    unsigned int max_y = 0;
924
    unsigned int min_x = width;
925
    unsigned int max_x = 0;
926
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
927
    while (!color_queue.empty() && !aborted) {
6839 by cilix42
Next roud of NR ==> Geom conversion
928
        Geom::Point color_point = color_queue.front();
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
929
        color_queue.pop();
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
930
6839 by cilix42
Next roud of NR ==> Geom conversion
931
        int cx = (int)color_point[Geom::X];
932
        int cy = (int)color_point[Geom::Y];
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
933
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
934
        guint32 orig_color = get_pixel(px, cx, cy, stride);
935
        bci.merged_orig_pixel = compose_onto(orig_color, dtc);
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
936
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
937
        unsigned char *trace_t = get_trace_pixel(trace_px, cx, cy, width);
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
938
        if (!is_pixel_checked(trace_t) && !is_pixel_colored(trace_t)) {
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
939
            if (check_if_pixel_is_paintable(px, trace_px, cx, cy, orig_color, bci)) {
3447 by johncoswell
Include new routines for building the fill point queue in a standard way
940
                shift_point_onto_queue(&fill_queue, bci.max_queue_size, trace_t, cx, cy);
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
941
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
942
                if (!first_run) {
3051 by johncoswell
Some additional Paint Bucket optimizations and cleanup
943
                    for (unsigned int y = 0; y < height; y++) {
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
944
                        trace_t = get_trace_pixel(trace_px, 0, y, width);
3051 by johncoswell
Some additional Paint Bucket optimizations and cleanup
945
                        for (unsigned int x = 0; x < width; x++) {
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
946
                            clear_pixel_paintability(trace_t);
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
947
                            trace_t++;
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
948
                        }
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
949
                    }
950
                }
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
951
                first_run = false;
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
952
            }
2931 by johncoswell
Improve fill dragging by increasing drag tolerance and preventing already-filled pixels from being checked in gradient fills
953
        }
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
954
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
955
        unsigned long old_fill_queue_size = fill_queue.size();
956
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
957
        while (!fill_queue.empty() && !aborted) {
6839 by cilix42
Next roud of NR ==> Geom conversion
958
            Geom::Point cp = fill_queue.front();
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
959
960
            if (bci.radius == 0) {
961
                unsigned long new_fill_queue_size = fill_queue.size();
962
5096 by johncoswell
Add doxygen comments to flood-context.cpp
963
                /*
964
                 * To reduce the number of points in the fill queue, periodically
965
                 * resort all of the points in the queue so that scanline checks
966
                 * can complete more quickly.  A point cannot be checked twice
967
                 * in a normal scanline checks, so forcing scanline checks to start
968
                 * from one corner of the rendered area as often as possible
969
                 * will reduce the number of points that need to be checked and queued.
970
                 */
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
971
                if (new_fill_queue_size > sort_size_threshold) {
972
                    if (new_fill_queue_size > old_fill_queue_size) {
973
                        std::sort(fill_queue.begin(), fill_queue.end(), sort_fill_queue_vertical);
974
6839 by cilix42
Next roud of NR ==> Geom conversion
975
                        std::deque<Geom::Point>::iterator start_sort = fill_queue.begin();
976
                        std::deque<Geom::Point>::iterator end_sort = fill_queue.begin();
977
                        unsigned int sort_y = (unsigned int)cp[Geom::Y];
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
978
                        unsigned int current_y = sort_y;
979
                        
6839 by cilix42
Next roud of NR ==> Geom conversion
980
                        for (std::deque<Geom::Point>::iterator i = fill_queue.begin(); i != fill_queue.end(); i++) {
981
                            Geom::Point current = *i;
982
                            current_y = (unsigned int)current[Geom::Y];
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
983
                            if (current_y != sort_y) {
984
                                if (start_sort != end_sort) {
985
                                    std::sort(start_sort, end_sort, sort_fill_queue_horizontal);
986
                                }
987
                                sort_y = current_y;
988
                                start_sort = i;
989
                            }
990
                            end_sort = i;
991
                        }
992
                        if (start_sort != end_sort) {
993
                            std::sort(start_sort, end_sort, sort_fill_queue_horizontal);
994
                        }
995
                        
996
                        cp = fill_queue.front();
997
                    }
998
                }
999
1000
                old_fill_queue_size = new_fill_queue_size;
1001
            }
1002
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
1003
            fill_queue.pop_front();
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
1004
6839 by cilix42
Next roud of NR ==> Geom conversion
1005
            int x = (int)cp[Geom::X];
1006
            int y = (int)cp[Geom::Y];
4080 by johncoswell
better paint bucket queue handling; queue points are sorted and cleaned up more efficiently now
1007
5479 by johncoswell
Only trace the painted area of the screen with each fill, reducing memory usage.
1008
            min_y = MIN((unsigned int)y, min_y);
1009
            max_y = MAX((unsigned int)y, max_y);
1010
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
1011
            unsigned char *trace_t = get_trace_pixel(trace_px, x, y, width);
3044 by johncoswell
Improve auto gap algorithm and move some "magic numbers" pixel setting code into separate functions
1012
            if (!is_pixel_checked(trace_t)) {
3051 by johncoswell
Some additional Paint Bucket optimizations and cleanup
1013
                mark_pixel_checked(trace_t);
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
1014
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
1015
                if (y == 0) {
6839 by cilix42
Next roud of NR ==> Geom conversion
1016
                    if (bbox->min()[Geom::Y] > screen.min()[Geom::Y]) {
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
1017
                        aborted = true; break;
1018
                    } else {
1019
                        reached_screen_boundary = true;
1020
                    }
1021
                }
1022
1023
                if (y == y_limit) {
6839 by cilix42
Next roud of NR ==> Geom conversion
1024
                    if (bbox->max()[Geom::Y] < screen.max()[Geom::Y]) {
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
1025
                        aborted = true; break;
1026
                    } else {
1027
                        reached_screen_boundary = true;
1028
                    }
1029
                }
1030
1031
                bci.is_left = true;
1032
                bci.x = x;
1033
                bci.y = y;
1034
5479 by johncoswell
Only trace the painted area of the screen with each fill, reducing memory usage.
1035
                ScanlineCheckResult result = perform_bitmap_scanline_check(&fill_queue, px, trace_px, orig_color, bci, &min_x, &max_x);
3048 by johncoswell
Implement various small paint bucket optimizations and cleanups
1036
1037
                switch (result) {
1038
                    case SCANLINE_CHECK_ABORTED:
1039
                        aborted = true;
1040
                        break;
1041
                    case SCANLINE_CHECK_BOUNDARY:
1042
                        reached_screen_boundary = true;
1043
                        break;
1044
                    default:
1045
                        break;
1046
                }
1047
3051 by johncoswell
Some additional Paint Bucket optimizations and cleanup
1048
                if (bci.x < width) {
5478 by johncoswell
Make parameter tracking for Paint Bucket less memory-intensive.
1049
                    trace_t++;
3051 by johncoswell
Some additional Paint Bucket optimizations and cleanup
1050
                    if (!is_pixel_checked(trace_t) && !is_pixel_queued(trace_t)) {
1051
                        mark_pixel_checked(trace_t);
1052
                        bci.is_left = false;
1053
                        bci.x = x + 1;
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
1054
5479 by johncoswell
Only trace the painted area of the screen with each fill, reducing memory usage.
1055
                        result = perform_bitmap_scanline_check(&fill_queue, px, trace_px, orig_color, bci, &min_x, &max_x);
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
1056
3051 by johncoswell
Some additional Paint Bucket optimizations and cleanup
1057
                        switch (result) {
1058
                            case SCANLINE_CHECK_ABORTED:
1059
                                aborted = true;
1060
                                break;
1061
                            case SCANLINE_CHECK_BOUNDARY:
1062
                                reached_screen_boundary = true;
1063
                                break;
1064
                            default:
1065
                                break;
1066
                        }
1067
                    }
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
1068
                }
2639 by johncoswell
Clean up indentation
1069
            }
3320 by johncoswell
Various small cleanups and optimizations to Paint Bucket tool.
1070
1071
            bci.current_step++;
1072
1073
            if (bci.current_step > bci.max_queue_size) {
1074
                aborted = true;
1075
            }
2639 by johncoswell
Clean up indentation
1076
        }
2432 by johncoswell
Add flood fill tool
1077
    }
1078
    
1079
    g_free(px);
1080
    
2434 by johncoswell
Prevent flood fills from leaking out of fill area
1081
    if (aborted) {
2639 by johncoswell
Clean up indentation
1082
        g_free(trace_px);
1083
        desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("<b>Area is not bounded</b>, cannot fill."));
1084
        return;
2434 by johncoswell
Prevent flood fills from leaking out of fill area
1085
    }
1086
    
2538 by mental
adapt code to new Maybe/bbox regime
1087
    if (reached_screen_boundary) {
2639 by johncoswell
Clean up indentation
1088
        desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("<b>Only the visible part of the bounded area was filled.</b> If you want to fill all of the area, undo, zoom out, and fill again.")); 
2538 by mental
adapt code to new Maybe/bbox regime
1089
    }
5479 by johncoswell
Only trace the painted area of the screen with each fill, reducing memory usage.
1090
1091
    unsigned int trace_padding = bci.radius + 1;
1092
    if (min_y > trace_padding) { min_y -= trace_padding; }
1093
    if (max_y < (y_limit - trace_padding)) { max_y += trace_padding; }
1094
    if (min_x > trace_padding) { min_x -= trace_padding; }
1095
    if (max_x < (width - 1 - trace_padding)) { max_x += trace_padding; }
1096
6839 by cilix42
Next roud of NR ==> Geom conversion
1097
    Geom::Point min_start = Geom::Point(min_x, min_y);
2538 by mental
adapt code to new Maybe/bbox regime
1098
    
6839 by cilix42
Next roud of NR ==> Geom conversion
1099
    affine = scale * Geom::Translate(-origin * scale - min_start);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1100
    Geom::Affine inverted_affine = Geom::Affine(affine).inverse();
2432 by johncoswell
Add flood fill tool
1101
    
5479 by johncoswell
Only trace the painted area of the screen with each fill, reducing memory usage.
1102
    do_trace(bci, trace_px, desktop, inverted_affine, min_x, max_x, min_y, max_y, union_with_selection);
2432 by johncoswell
Add flood fill tool
1103
2538 by mental
adapt code to new Maybe/bbox regime
1104
    g_free(trace_px);
1105
    
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1106
    DocumentUndo::done(document, SP_VERB_CONTEXT_PAINTBUCKET, _("Fill bounded area"));
2432 by johncoswell
Add flood fill tool
1107
}
1108
1109
static gint sp_flood_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event)
1110
{
1111
    gint ret = FALSE;
1112
2603 by johncoswell
Add ctrl+click to paint bucket to change clicked object's fill and stroke to current setting
1113
    SPDesktop *desktop = event_context->desktop;
1114
2432 by johncoswell
Add flood fill tool
1115
    switch (event->type) {
1116
    case GDK_BUTTON_PRESS:
3341 by buliabyak
due to the order of processing events, we must disable lmb handling in children contexts so that parent event context can handle it for space panning
1117
        if ((event->button.state & GDK_CONTROL_MASK) && event->button.button == 1 && !event_context->space_panning) {
6839 by cilix42
Next roud of NR ==> Geom conversion
1118
            Geom::Point const button_w(event->button.x,
1119
                                       event->button.y);
2603 by johncoswell
Add ctrl+click to paint bucket to change clicked object's fill and stroke to current setting
1120
            
1121
            SPItem *item = sp_event_context_find_item (desktop, button_w, TRUE, TRUE);
1122
            
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1123
            // Set style
1124
            desktop->applyCurrentOrToolStyle(item, "/tools/paintbucket", false);
1125
            DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_PAINTBUCKET, _("Set style on object"));
2603 by johncoswell
Add ctrl+click to paint bucket to change clicked object's fill and stroke to current setting
1126
            ret = TRUE;
1127
        }
2432 by johncoswell
Add flood fill tool
1128
        break;
1129
    default:
1130
        break;
1131
    }
1132
1133
    if (((SPEventContextClass *) parent_class)->item_handler) {
1134
        ret = ((SPEventContextClass *) parent_class)->item_handler(event_context, item, event);
1135
    }
1136
1137
    return ret;
1138
}
1139
1140
static gint sp_flood_context_root_handler(SPEventContext *event_context, GdkEvent *event)
1141
{
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
1142
    static bool dragging;
1143
    
2432 by johncoswell
Add flood fill tool
1144
    gint ret = FALSE;
2598 by buliabyak
display busy cursor while filling
1145
    SPDesktop *desktop = event_context->desktop;
1146
2432 by johncoswell
Add flood fill tool
1147
    switch (event->type) {
1148
    case GDK_BUTTON_PRESS:
3341 by buliabyak
due to the order of processing events, we must disable lmb handling in children contexts so that parent event context can handle it for space panning
1149
        if (event->button.button == 1 && !event_context->space_panning) {
2603 by johncoswell
Add ctrl+click to paint bucket to change clicked object's fill and stroke to current setting
1150
            if (!(event->button.state & GDK_CONTROL_MASK)) {
6839 by cilix42
Next roud of NR ==> Geom conversion
1151
                Geom::Point const button_w(event->button.x,
1152
                                           event->button.y);
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
1153
    
2946 by johncoswell
Add check for hidden/locked layer
1154
                if (Inkscape::have_viable_layer(desktop, event_context->defaultMessageContext())) {
1155
                    // save drag origin
6839 by cilix42
Next roud of NR ==> Geom conversion
1156
                    event_context->xp = (gint) button_w[Geom::X];
1157
                    event_context->yp = (gint) button_w[Geom::Y];
2946 by johncoswell
Add check for hidden/locked layer
1158
                    event_context->within_tolerance = true;
4237 by johncoswell
fix possible crash where event_context is destroyed during fill operation due to tool switch
1159
                      
2946 by johncoswell
Add check for hidden/locked layer
1160
                    dragging = true;
1161
                    
6839 by cilix42
Next roud of NR ==> Geom conversion
1162
                    Geom::Point const p(desktop->w2d(button_w));
6630 by cilix42
Removal of SP_ACTIVE_DESKTOP, next take
1163
                    Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_TOUCHPATH);
1164
                    Inkscape::Rubberband::get(desktop)->start(desktop, p);
2946 by johncoswell
Add check for hidden/locked layer
1165
                }
2900 by johncoswell
Add ability to drag cursor while holding alt to add multiple points to paint bucket action
1166
            }
1167
        }
1168
    case GDK_MOTION_NOTIFY:
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
1169
        if ( dragging
3341 by buliabyak
due to the order of processing events, we must disable lmb handling in children contexts so that parent event context can handle it for space panning
1170
             && ( event->motion.state & GDK_BUTTON1_MASK ) && !event_context->space_panning)
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
1171
        {
1172
            if ( event_context->within_tolerance
1173
                 && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance )
1174
                 && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) {
1175
                break; // do not drag if we're within tolerance from origin
1176
            }
1177
            
1178
            event_context->within_tolerance = false;
1179
            
6839 by cilix42
Next roud of NR ==> Geom conversion
1180
            Geom::Point const motion_pt(event->motion.x, event->motion.y);
1181
            Geom::Point const p(desktop->w2d(motion_pt));
6630 by cilix42
Removal of SP_ACTIVE_DESKTOP, next take
1182
            if (Inkscape::Rubberband::get(desktop)->is_started()) {
1183
                Inkscape::Rubberband::get(desktop)->move(p);
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
1184
                event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw over</b> areas to add to fill, hold <b>Alt</b> for touch fill"));
2900 by johncoswell
Add ability to drag cursor while holding alt to add multiple points to paint bucket action
1185
                gobble_motion_events(GDK_BUTTON1_MASK);
1186
            }
1187
        }
1188
        break;
1189
1190
    case GDK_BUTTON_RELEASE:
3341 by buliabyak
due to the order of processing events, we must disable lmb handling in children contexts so that parent event context can handle it for space panning
1191
        if (event->button.button == 1 && !event_context->space_panning) {
9012.1.255 by Josh Andler
Patch by Daniel_J for 522327
1192
            Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
2900 by johncoswell
Add ability to drag cursor while holding alt to add multiple points to paint bucket action
1193
            if (r->is_started()) {
2603 by johncoswell
Add ctrl+click to paint bucket to change clicked object's fill and stroke to current setting
1194
                // set "busy" cursor
2648 by buliabyak
use desktop method to set waiting cursor; do not try to restore it if someone already did it (fixes crash when you switch to another tool while filling)
1195
                desktop->setWaitingCursor();
2683 by buliabyak
fix crash when you quickly click in two areas and then press a key to go to another tool before filling is finished
1196
1197
                if (SP_IS_EVENT_CONTEXT(event_context)) { 
1198
                    // Since setWaitingCursor runs main loop iterations, we may have already left this tool!
1199
                    // So check if the tool is valid before doing anything
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
1200
                    dragging = false;
2683 by buliabyak
fix crash when you quickly click in two areas and then press a key to go to another tool before filling is finished
1201
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
1202
                    bool is_point_fill = event_context->within_tolerance;
1203
                    bool is_touch_fill = event->button.state & GDK_MOD1_MASK;
1204
                    
1205
                    sp_flood_do_flood_fill(event_context, event, event->button.state & GDK_SHIFT_MASK, is_point_fill, is_touch_fill);
1206
                    
1207
                    desktop->clearWaitingCursor();
2683 by buliabyak
fix crash when you quickly click in two areas and then press a key to go to another tool before filling is finished
1208
                    // restore cursor when done; note that it may already be different if e.g. user 
1209
                    // switched to another tool during interruptible tracing or drawing, in which case do nothing
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
1210
2683 by buliabyak
fix crash when you quickly click in two areas and then press a key to go to another tool before filling is finished
1211
                    ret = TRUE;
1212
                }
2927 by johncoswell
Start building drag fill that uses colors of all points under drag path
1213
2900 by johncoswell
Add ability to drag cursor while holding alt to add multiple points to paint bucket action
1214
                r->stop();
4237 by johncoswell
fix possible crash where event_context is destroyed during fill operation due to tool switch
1215
1216
                if (SP_IS_EVENT_CONTEXT(event_context)) {
1217
                    event_context->defaultMessageContext()->clear();
1218
                }
2603 by johncoswell
Add ctrl+click to paint bucket to change clicked object's fill and stroke to current setting
1219
            }
2432 by johncoswell
Add flood fill tool
1220
        }
1221
        break;
2538 by mental
adapt code to new Maybe/bbox regime
1222
    case GDK_KEY_PRESS:
1223
        switch (get_group0_keyval (&event->key)) {
1224
        case GDK_Up:
1225
        case GDK_Down:
1226
        case GDK_KP_Up:
1227
        case GDK_KP_Down:
1228
            // prevent the zoom field from activation
1229
            if (!MOD__CTRL_ONLY)
1230
                ret = TRUE;
1231
            break;
1232
        default:
1233
            break;
1234
        }
1235
        break;
2432 by johncoswell
Add flood fill tool
1236
    default:
1237
        break;
1238
    }
1239
1240
    if (!ret) {
1241
        if (((SPEventContextClass *) parent_class)->root_handler) {
1242
            ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event);
1243
        }
1244
    }
1245
1246
    return ret;
1247
}
1248
1249
1250
static void sp_flood_finish(SPFloodContext *rc)
1251
{
1252
    rc->_message_context->clear();
1253
1254
    if ( rc->item != NULL ) {
1255
        SPDesktop * desktop;
1256
1257
        desktop = SP_EVENT_CONTEXT_DESKTOP(rc);
1258
1259
        SP_OBJECT(rc->item)->updateRepr();
1260
1261
        sp_canvas_end_forced_full_redraws(desktop->canvas);
1262
1263
        sp_desktop_selection(desktop)->set(rc->item);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1264
        DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_PAINTBUCKET,
2639 by johncoswell
Clean up indentation
1265
                        _("Fill bounded area"));
2432 by johncoswell
Add flood fill tool
1266
1267
        rc->item = NULL;
1268
    }
1269
}
1270
2866 by joncruz
Switched paint bucket toolbar to stock GTK+ toobar, including minor MVC cleanup on flood-context
1271
void flood_channels_set_channels( gint channels )
2561 by johncoswell
Begin work on selectable color channels for paint bucket, starting with visible colors and alpha
1272
{
6885 by Ted Gould
From trunk
1273
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1274
    prefs->setInt("/tools/paintbucket/channels", channels);
2561 by johncoswell
Begin work on selectable color channels for paint bucket, starting with visible colors and alpha
1275
}
2564 by johncoswell
Add units selector to offset and remove offset range limits
1276
2432 by johncoswell
Add flood fill tool
1277
/*
1278
  Local Variables:
1279
  mode:c++
1280
  c-file-style:"stroustrup"
1281
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1282
  indent-tabs-mode:nil
1283
  fill-column:99
1284
  End:
1285
*/
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1286
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :