Fix out-of-bounds waveform image rendering.
[ardour.git] / libs / canvas / wave_view.cc
index 17ee8609ff79dc641d084ea5bba29430f8a0514d..039979c3a9f7d62277a5fd383c814c5a46f54830 100644 (file)
@@ -158,7 +158,7 @@ WaveView::~WaveView ()
 string
 WaveView::debug_name() const
 {
-       return _region->name() + string (":") + PBD::to_string (_channel+1, std::dec);
+       return _region->name() + string (":") + PBD::to_string (_channel+1);
 }
 
 void
@@ -800,7 +800,7 @@ WaveView::get_image (framepos_t start, framepos_t end, bool& full_image) const
 
                DEBUG_TRACE (DEBUG::WaveView, string_compose ("%1 CR %2 stop? %3 image %4\n", this, current_request,
                                        (current_request ? current_request->should_stop() : false),
-                                       (current_request ? current_request->image : 0)));
+                                       (current_request ? (current_request->image ? "yes" : "no") : "n/a")));
 
                if (current_request && !current_request->should_stop() && current_request->image) {
 
@@ -912,10 +912,15 @@ WaveView::desired_image_width () const
         * We want at least 1 canvas width's worth, but if that
         * represents less than 1/10th of a second, use 1/10th of
         * a second instead.
+        *
+        * ..unless at high-zoom level 100ms would be more than 2^15px
+        * (cairo image limit), note that generate_image() uses twice this
+        * width (left/right of the center of the request range.
         */
 
        framecnt_t canvas_width_samples = _canvas->visible_area().width() * _samples_per_pixel;
-       const framecnt_t one_tenth_of_second = _region->session().frame_rate() / 10;
+       const framecnt_t one_tenth_of_second = std::min (_region->session().frame_rate() / 10,  (framecnt_t)floor (16383.0 / _samples_per_pixel));
+
 
        if (canvas_width_samples > one_tenth_of_second) {
                return  canvas_width_samples;
@@ -927,6 +932,7 @@ WaveView::desired_image_width () const
 void
 WaveView::queue_get_image (boost::shared_ptr<const ARDOUR::Region> region, framepos_t start, framepos_t end) const
 {
+       DEBUG_TRACE (DEBUG::WaveView, string_compose ("%1: queue image from %2 .. %3\n", name, start, end));
        boost::shared_ptr<WaveViewThreadRequest> req (new WaveViewThreadRequest);
 
        req->type = WaveViewThreadRequest::Draw;
@@ -983,13 +989,14 @@ WaveView::generate_image (boost::shared_ptr<WaveViewThreadRequest> req, bool in_
                const framepos_t center = req->start + ((req->end - req->start) / 2);
                const framecnt_t image_samples = req->width;
 
-               /* we can request data from anywhere in the Source, between 0 and its length
-                */
+               /* we can request data from anywhere in the Source, between 0 and its length */
 
                framepos_t sample_start = max (_region_start, (center - image_samples));
                framepos_t sample_end = min (center + image_samples, region_end());
                const int n_peaks = std::max (1LL, llrint (ceil ((sample_end - sample_start) / (req->samples_per_pixel))));
 
+               DEBUG_TRACE (DEBUG::WaveView, string_compose ("%1: request %2 .. %3 width: %4; render %5 .. %6 (%7)\n", name, req->start, req->end, req->width, sample_start, sample_end, n_peaks));
+
                assert (n_peaks > 0 && n_peaks < 32767);
 
                boost::scoped_array<ARDOUR::PeakData> peaks (new PeakData[n_peaks]);
@@ -1101,13 +1108,13 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
 
        /* Now lets get the intersection with the area we've been asked to draw */
 
-       boost::optional<Rect> d = self.intersection (area);
+       Rect d = self.intersection (area);
 
        if (!d) {
                return;
        }
 
-       Rect draw = d.get();
+       Rect draw = d;
 
        /* "draw" is now a rectangle that defines the rectangle we need to
         * update/render the waveview into, in window coordinate space.
@@ -1276,7 +1283,7 @@ WaveView::compute_bounding_box () const
        if (_region) {
                _bounding_box = Rect (0.0, 0.0, region_length() / _samples_per_pixel, _height);
        } else {
-               _bounding_box = boost::optional<Rect> ();
+               _bounding_box = Rect ();
        }
 
        _bounding_box_dirty = false;