diff --git a/src/stage/model/zoom-window.hpp b/src/stage/model/zoom-window.hpp index 215c82c57..f2c68ec0b 100644 --- a/src/stage/model/zoom-window.hpp +++ b/src/stage/model/zoom-window.hpp @@ -60,6 +60,16 @@ ** - scale factor and visible window line up logically ** - scale factor produces precise reproducible values ** + ** ## Safety Guards + ** + ** Most setters require lib::time::TimeSpan or lib::time::Duration as _value arguments;_ + ** based on those entities internal definition, they can be assumed to be sanitised, + ** within TimeValue bounds and properly oriented. Other setters taking possibly negative + ** numbers are prepared to handle these (e.g. as offset). Range checks are in place to + ** prevent possibly dangerous numbers from infesting the calculations. + ** @note rational integral arithmetics can be insidious, since normalisation requires + ** frequent multiplications, and large denominators might cause numeric overflow. + ** ** ## Change listener ** ** A single change listener lambda can be installed (as of 10/2022 this is considered sufficient, @@ -379,7 +389,7 @@ namespace model { nudgeVisiblePos (int steps) { FSecs dur{afterWin_-startWin_}; // navigate half window steps - setVisibleRange (TimeSpan{Time{startWin_ + dur*steps/2} + setVisibleRange (TimeSpan{Time{startWin_ + (dur*steps)/2} , dur}); } @@ -761,6 +771,8 @@ namespace model { * relative to the overall canvas. Implemented using a cubic parabola, which moves quick * away from the boundaries, while hovering most of the time in the middle area. * @return factor effectively between 0 ... 1 (inclusive) + * @warning in case of a "poisonous" input the calculation may go astray; + * yet results are limited at least... */ static Rat parabolicAnchorRule (Rat posFactor) @@ -769,6 +781,7 @@ namespace model { posFactor = (2*posFactor - 1); // -1 ... +1 posFactor = posFactor*posFactor*posFactor; // -1 ... +1 but accelerating towards boundaries posFactor = (posFactor + 1) / 2; // 0 ... 1 + posFactor = util::limited (0, posFactor, 1); return posFactor; } }; diff --git a/tests/stage/model/zoom-window-test.cpp b/tests/stage/model/zoom-window-test.cpp index 6718b0117..6dca9af18 100644 --- a/tests/stage/model/zoom-window-test.cpp +++ b/tests/stage/model/zoom-window-test.cpp @@ -86,6 +86,8 @@ namespace test { verify_scroll(); verify_changeNotification(); + + toxic_corner_cases(); } @@ -482,6 +484,53 @@ namespace test { CHECK (win.px_per_sec() == 400); CHECK (wuz.px_per_sec() == 20); } + + + /** @test verify safeguards when used in extreme corner cases */ + void + toxic_corner_cases() + { + { + ZoomWindow win{0, TimeSpan{_t(0), FSecs(0)}}; + CHECK (win.visible() == TimeSpan(_t(0), _t(23))); // uses DEFAULT_CANVAS instead of empty TimeSpan + CHECK (win.px_per_sec() == 25); // falls back on default initial zoom factor + CHECK (win.pxWidth() == 575); // allocates pixels in accordance to default + + win.setOverallDuration(Duration{FSecs(50)}); + win.setVisibleDuration(Duration{FSecs(0)}); + CHECK (win.overallSpan() == TimeSpan(_t(0), _t(50))); + CHECK (win.visible() == TimeSpan(_t(0), _t(23))); // falls back to DEFAULT_CANVAS size + CHECK (win.pxWidth() == 575); // allocates pixels in accordance to default + + win.calibrateExtension(0); + CHECK (win.px_per_sec() == 25); // stays at default zoom factor + CHECK (win.pxWidth() == 1); // retains 1px window size + CHECK (win.visible().duration() == _t(1,25)); // visible window has thus 1/25s duration + + win.setOverallRange(TimeSpan(_t(10), _t(0))); + SHOW_EXPR (win.overallSpan()); + SHOW_EXPR (win.visible()); + SHOW_EXPR (_raw(win.visible().duration())); + SHOW_EXPR (win.px_per_sec()); + SHOW_EXPR (win.pxWidth()); + + CHECK (TimeSpan(_t(10), _t(0)).duration() == Duration(FSecs(10))); // TimeSpan is always properly oriented by construction + Duration evilReversed = static_cast (_t(-10)); + SHOW_EXPR (evilReversed); + SHOW_EXPR (TimeSpan(_t(20), evilReversed)); + + } + { + ZoomWindow win{}; +// SHOW_EXPR(win.overallSpan()); +// SHOW_EXPR(_raw(win.visible().duration())); +// SHOW_EXPR(win.px_per_sec()); +// SHOW_EXPR(win.pxWidth()); +// CHECK (win.visible() == TimeSpan(_t(0), _t(23))); +// CHECK (win.px_per_sec() == 25); +// CHECK (win.pxWidth() == 575); + } + } }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 23d2ea3cd..da5deaec2 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -1379,7 +1379,7 @@ - + @@ -39533,11 +39533,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ weil es direkt in das Feld px_per_second_ geht +

+ +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -39545,6 +39704,19 @@ + + + + + + + + + + + + + @@ -43861,7 +44033,7 @@ - +