From 1ff75a5c0c182beb3c15bf3a44298ef6d449b1d2 Mon Sep 17 00:00:00 2001 From: Bill Kendrick Date: Mon, 15 Nov 2021 20:40:26 -0800 Subject: [PATCH 1/4] Stop recursive flood fill at depth of 20K Attempt to void crashing (by blowing up the stack) when doing a flood-fill of a complicated shape on a large canvas (e.g., `tuxpaint --3000x2000` with `starters/mosaic.svg`). --- docs/CHANGES.txt | 5 +++++ src/fill.c | 16 ++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index feed8c26b..2d4a0dae8 100644 --- a/docs/CHANGES.txt +++ b/docs/CHANGES.txt @@ -192,6 +192,11 @@ $Id$ (e.g., when returning from the "Open" dialog). (Closes https://sourceforge.net/p/tuxpaint/feature-requests/186/) + * Attempt to void crashing (by blowing up the stack) when doing + a flood-fill of a complicated shape on a large canvas + (e.g., `tuxpaint --3000x2000` with `starters/mosaic.svg`). + (h/t Yang for reporting, and Pere for confirming) + * Ports & Building ---------------- * Fix compilation error on Linux with HOST environment variable set. diff --git a/src/fill.c b/src/fill.c index c2e68e6d7..5664a4869 100644 --- a/src/fill.c +++ b/src/fill.c @@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (See COPYING.txt) - Last updated: October 24, 2021 + Last updated: November 15, 2021 $Id$ */ @@ -64,7 +64,7 @@ double colors_close(SDL_Surface * canvas, Uint32 c1, Uint32 c2); Uint32 blend(SDL_Surface * canvas, Uint32 draw_colr, Uint32 old_colr, double pct); -void simulate_flood_fill_outside_check(SDL_Surface * screen, SDL_Surface * last, SDL_Surface * canvas, int x, int y, Uint32 cur_colr, Uint32 old_colr, int * x1, int * y1, int * x2, int * y2, Uint8 * touched, int y_outside); +void simulate_flood_fill_outside_check(SDL_Surface * screen, SDL_Surface * last, SDL_Surface * canvas, int x, int y, Uint32 cur_colr, Uint32 old_colr, int * x1, int * y1, int * x2, int * y2, Uint8 * touched, int y_outside, Uint32 cnt); void draw_brush_fill_single(SDL_Surface * canvas, int x, int y, Uint32 draw_color, Uint8 * touched); @@ -133,10 +133,10 @@ Uint32 blend(SDL_Surface * canvas, Uint32 draw_colr, Uint32 old_colr, double pct } void simulate_flood_fill(SDL_Surface * screen, SDL_Surface * last, SDL_Surface * canvas, int x, int y, Uint32 cur_colr, Uint32 old_colr, int * x1, int * y1, int * x2, int * y2, Uint8 * touched) { - simulate_flood_fill_outside_check(screen, last, canvas, x, y, cur_colr, old_colr, x1, y1, x2, y2, touched, 0); + simulate_flood_fill_outside_check(screen, last, canvas, x, y, cur_colr, old_colr, x1, y1, x2, y2, touched, 0, 0); } -void simulate_flood_fill_outside_check(SDL_Surface * screen, SDL_Surface * last, SDL_Surface * canvas, int x, int y, Uint32 cur_colr, Uint32 old_colr, int * x1, int * y1, int * x2, int * y2, Uint8 * touched, int y_outside) +void simulate_flood_fill_outside_check(SDL_Surface * screen, SDL_Surface * last, SDL_Surface * canvas, int x, int y, Uint32 cur_colr, Uint32 old_colr, int * x1, int * y1, int * x2, int * y2, Uint8 * touched, int y_outside, Uint32 cnt) { int fillL, fillR, narrowFillL, narrowFillR, i, outside; double in_line, closeness; @@ -144,6 +144,10 @@ void simulate_flood_fill_outside_check(SDL_Surface * screen, SDL_Surface * last, Uint32 px_colr; Uint8 touch_byt; + /* Don't blow up the stack! */ + /* FIXME: Would be better to do this a more reliable way */ + if (cnt >= 20000) + return; /* "Same" color? No need to fill */ if (!would_flood_fill(canvas, cur_colr, old_colr)) @@ -313,7 +317,7 @@ void simulate_flood_fill_outside_check(SDL_Surface * screen, SDL_Surface * last, ) ) { - simulate_flood_fill_outside_check(screen, last, canvas, i, y - 1, cur_colr, old_colr, x1, y1, x2, y2, touched, y_outside + 1); + simulate_flood_fill_outside_check(screen, last, canvas, i, y - 1, cur_colr, old_colr, x1, y1, x2, y2, touched, y_outside + 1, cnt + 1); } px_colr = getpixels[last->format->BytesPerPixel] (last, i, y + 1); @@ -325,7 +329,7 @@ void simulate_flood_fill_outside_check(SDL_Surface * screen, SDL_Surface * last, ) ) { - simulate_flood_fill_outside_check(screen, last, canvas, i, y + 1, cur_colr, old_colr, x1, y1, x2, y2, touched, y_outside + 1); + simulate_flood_fill_outside_check(screen, last, canvas, i, y + 1, cur_colr, old_colr, x1, y1, x2, y2, touched, y_outside + 1, cnt + 1); } } } From 57cea8365536da5845520e94ed74d7cc4f117b9e Mon Sep 17 00:00:00 2001 From: Bill Kendrick Date: Mon, 15 Nov 2021 23:53:15 -0800 Subject: [PATCH 2/4] Added rotating dash brush --- data/brushes/rotating_dash.dat | 2 ++ data/brushes/rotating_dash.png | Bin 0 -> 4556 bytes docs/CHANGES.txt | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 data/brushes/rotating_dash.dat create mode 100644 data/brushes/rotating_dash.png diff --git a/data/brushes/rotating_dash.dat b/data/brushes/rotating_dash.dat new file mode 100644 index 000000000..e8180d852 --- /dev/null +++ b/data/brushes/rotating_dash.dat @@ -0,0 +1,2 @@ +rotate +spacing=10 diff --git a/data/brushes/rotating_dash.png b/data/brushes/rotating_dash.png new file mode 100644 index 0000000000000000000000000000000000000000..9457fee7993e910a2f20b5914e50864a033e3642 GIT binary patch literal 4556 zcmeHKdsGu=77v0T2rASnqQDT2Y(QYqzH@H-fMJcfWTRq*F# zYbGJmPE#zF{rcmLGxk3W@y!1I(*@O$H8URqG> z=^jvp5nc4 z*Iv4GqFGSzd{xlXdAGZwW;{Fe6wW^sykfcU(rT|O24(xU?S}1-m9bf!wO>4|?R@>Z z#C6Ti($>7H6nj(MvEX9C@MVG6@h|Rtdj9s|FHgx-ejynL{Z_JlCw7E*zwvkX`42a~ zN$Y)~K=W+QPE%r+J^mqYTGav6^l`4rlG|o#S@B$2RMY`)t9k0ZsQ9Z&q5OH_Yx~`C zQCGKAuiQ9Po7%P`AT~Mpeu>$8pET%z#W!G?`<#P2B;j+<%<`QY9d|jd$oEJH>32Ef z;=ztM{~+qP&sf(+e;3((UCL26-q{)SepOM>utNW9gS87ACZ9J*^Zt5k+%~tEBKL+N zU(ZjuR36wkX6oYm*Ur8?T`VqKjVwtypmBEI5>Zj>)3vK={1Ml%)sxP6S12FlekCe; zbJU$!JnECsj!w_Q)dtptC7B9DG-mUsUg=9c{2TOgWtp=^c7M|5_z}>|fFXr7N~f{+ z%&X%IHik}=ZH3N|u0Ej(PyKHGiF3)-izY?1X%a3}?pCN%_Z(u6AI;gBv?8{8^S|@? z2X&P3%9d5>vti?tztzp$weRXk9O7^RnRpHfFzAf8a{u65GsH~AzT!=bU z^}>1Xfr?i4$1B^)Tq}P0!R2(;j+34zMC72)hq_$**SN-EwOD7mqwWXQoCt_%Srzu zPJ=U>R*f3)Oj#wWmtkgX|bT4pa;Hm5l)Vg-nG5?+G zu$qVEXGLAD{KLsBYgSn=%{KgIX`B!c?%YtI+;v|Wmi49i+WOj&E;kc=rhTM)5wfM? zhM%)U- zjt<|`^bd3MTEW{+gI8Fb^jVW|p;On78q>0^mUCc)_|afgB&nxMaFc45+%DLcbvGfQANCntxS6UH@J(qW!hEQS#jMo|v1;8=5wHq6d3T7wygZVWkT z#VxeiMw^TfgNf-(SvDz~4bGw7{0wHb`W?K{+QS0i1GZykn8!t6g8}aAVYMl;0Z30m zf9PRN1QQq5l2%ie1t%5Rq|p}K7lOdw`J1yWdPg|~4wHJ)08FhQDz9J2sVcSRod-if zI&CmJya3t#ENwLPo~(YkF(;04`X&P0-{JPN?ycQn46M{@iQI%|G3lw~QZ^G`LYQ!x zkT@>UaDo!+Z~=#+#0ZBk&`}&rh?5*XpCG~r9zqa^s1KCNXtiNRoMfN?IF|-EJRLy+ zLp}!&r+_0*$LEL%KEV-&iG(OZAyhcZ>jM#Qp@Awfec!AYC;~uXIx)uM^F*9*6a(2% z6v5Hql$b-1I8F)?K1T4nvmtQF6qCh(fp*dcES-eS#&kyvhHy!YMkQsVT;%pBr;SWs`&>5b*0h!ZR>qItlLY9zpf)(|^z`0SOw5>j=A`Y<1-i_HtWz^0o`rB=AL3?1RdcOu%>cY-ZXl{_YK$W=TI Z3IwZ2mQz$~s~5OpsT6VYeUsCc{1*WYs^b6v literal 0 HcmV?d00001 diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index 2d4a0dae8..bdc289664 100644 --- a/docs/CHANGES.txt +++ b/docs/CHANGES.txt @@ -8,7 +8,7 @@ http://www.tuxpaint.org/ $Id$ -2021.November.8 (0.9.27) +2021.November.15 (0.9.27) * New Magic Tools: ---------------- * "Lightning" - Draws a bolt of lightning striking between @@ -66,6 +66,8 @@ $Id$ arrow which can rotate at any angle, using the new "rotational" brush feature. + * Added "rotating dash" brush. + * Small icons appear on brush selection buttons denoting when the brush is animated and/or directional. (Closes https://sourceforge.net/p/tuxpaint/bugs/183/) From 6a52e33d35cd0eee9d062130294b51913024221f Mon Sep 17 00:00:00 2001 From: Bill Kendrick Date: Mon, 15 Nov 2021 23:57:12 -0800 Subject: [PATCH 3/4] Improve canvas update w/ rotating brushes --- src/tuxpaint.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tuxpaint.c b/src/tuxpaint.c index f19e5a660..64ecfde21 100644 --- a/src/tuxpaint.c +++ b/src/tuxpaint.c @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (See COPYING.txt) - June 14, 2002 - November 8, 2021 + June 14, 2002 - November 15, 2021 */ #include "platform.h" @@ -5993,7 +5993,7 @@ static void draw_blinking_cursor(void) */ static void brush_draw(int x1, int y1, int x2, int y2, int update) { - int dx, dy, y, frame_w, w, h; + int dx, dy, y, frame_w, w, h, sz; int orig_x1, orig_y1, orig_x2, orig_y2, tmp; int direction, r; float m, b; @@ -6100,7 +6100,8 @@ static void brush_draw(int x1, int y1, int x2, int y2, int update) if (update) { - update_canvas(orig_x1 - (w >> 1), orig_y1 - (h >> 1), orig_x2 + (w >> 1), orig_y2 + (h >> 1)); + sz = max(w,h); + update_canvas(orig_x1 - sz, orig_y1 - sz, orig_x2 + sz, orig_y2 + sz); } } From af8fd5b8a115a4b3386eecf04a1ef37d1d95ddcb Mon Sep 17 00:00:00 2001 From: Bill Kendrick Date: Tue, 16 Nov 2021 00:13:44 -0800 Subject: [PATCH 4/4] Attempts to improve rotated brushes * Rotating brush angle is now a double, not an int * Don't draw once on click; require some motion (does not affect directional brushes, which include a "no movement" shape in the middle of the brush bitmap) --- src/tuxpaint.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/tuxpaint.c b/src/tuxpaint.c index 64ecfde21..d2ad15675 100644 --- a/src/tuxpaint.c +++ b/src/tuxpaint.c @@ -1967,7 +1967,7 @@ SDL_Joystick *joystick; static void mainloop(void); static void brush_draw(int x1, int y1, int x2, int y2, int update); -static void blit_brush(int x, int y, int direction, int rotation, int * w, int * h); +static void blit_brush(int x, int y, int direction, double rotation, int * w, int * h); static void stamp_draw(int x, int y); static void rec_undo_buffer(void); @@ -5995,8 +5995,9 @@ static void brush_draw(int x1, int y1, int x2, int y2, int update) { int dx, dy, y, frame_w, w, h, sz; int orig_x1, orig_y1, orig_x2, orig_y2, tmp; - int direction, r; + int direction; float m, b; + double r; orig_x1 = x1; orig_y1 = y1; @@ -6017,22 +6018,22 @@ static void brush_draw(int x1, int y1, int x2, int y2, int update) direction = BRUSH_DIRECTION_NONE; - r = 0; + r = -1.0; if (brushes_directional[cur_brush] || brushes_rotate[cur_brush]) { r = brush_rotation(x1, y1, x2, y2); if (brushes_directional[cur_brush]) { - r = r + 22; - if (r < 0) - r = r + 360; + r = r + 22.0; + if (r < 0.0) + r = r + 360.0; if (x1 != x2 || y1 != y2) - direction = (r / 45); + direction = (r / 45.0); } else { - r = 270 - r; + r = 270.0 - r; } } @@ -6107,13 +6108,18 @@ static void brush_draw(int x1, int y1, int x2, int y2, int update) /** - * Reset the brush counter, such that the next - * attempt to draw something is guaranteed to - * do so, regardless of the brushe's spacing. + * Reset the brush counter, such that the next attempt to draw something + * is either (a) guaranteed to do so, regardless of the brush's spacing + * (for non-rotational brushes), or (b) requires the user to have moved + * far enough to get a good idea of the angle they're drawing + * (for rotational brushes). */ void reset_brush_counter(void) { - brush_counter = 999; + if (img_cur_brush_rotate) + brush_counter = 0; + else + brush_counter = 999; } @@ -6129,7 +6135,7 @@ void reset_brush_counter(void) * @param direction BRUSH_DIRECTION_... being drawn (for compass direction brushes) * @param rotation angle being drawn (for brushes which may rotate at any angle (0-360 degrees)) */ -static void blit_brush(int x, int y, int direction, int rotation, int * w, int * h) +static void blit_brush(int x, int y, int direction, double rotation, int * w, int * h) { SDL_Rect src, dest; @@ -6202,7 +6208,7 @@ static void blit_brush(int x, int y, int direction, int rotation, int * w, int * src.w = img_cur_brush_w; src.h = img_cur_brush_h; - if (img_cur_brush_rotate) + if (img_cur_brush_rotate && rotation != -1.0 /* only if we're moving */) { SDL_Surface * rotated_brush;