@@ -336,6 +336,7 @@ class PathClipper : public EmbeddedQueue<3>
336336 double m_initX;
337337 double m_initY;
338338 bool m_has_init;
339+ bool m_was_clipped;
339340
340341 public:
341342 PathClipper (VertexSource &source, bool do_clipping, double width, double height)
@@ -347,7 +348,8 @@ class PathClipper : public EmbeddedQueue<3>
347348 m_moveto(true ),
348349 m_initX(nan(" " )),
349350 m_initY(nan(" " )),
350- m_has_init(false )
351+ m_has_init(false ),
352+ m_was_clipped(false )
351353 {
352354 // empty
353355 }
@@ -361,7 +363,8 @@ class PathClipper : public EmbeddedQueue<3>
361363 m_moveto(true ),
362364 m_initX(nan(" " )),
363365 m_initY(nan(" " )),
364- m_has_init(false )
366+ m_has_init(false ),
367+ m_was_clipped(false )
365368 {
366369 m_cliprect.x1 -= 1.0 ;
367370 m_cliprect.y1 -= 1.0 ;
@@ -372,21 +375,29 @@ class PathClipper : public EmbeddedQueue<3>
372375 inline void rewind (unsigned path_id)
373376 {
374377 m_has_init = false ;
378+ m_was_clipped = false ;
375379 m_moveto = true ;
376380 m_source->rewind (path_id);
377381 }
378382
379- int draw_clipped_line (double x0, double y0, double x1, double y1)
383+ int draw_clipped_line (double x0, double y0, double x1, double y1,
384+ bool closed=false )
380385 {
381386 unsigned moved = agg::clip_line_segment (&x0, &y0, &x1, &y1, m_cliprect);
382387 // moved >= 4 - Fully clipped
383388 // moved & 1 != 0 - First point has been moved
384389 // moved & 2 != 0 - Second point has been moved
390+ m_was_clipped = m_was_clipped || (moved != 0 );
385391 if (moved < 4 ) {
386392 if (moved & 1 || m_moveto) {
387393 queue_push (agg::path_cmd_move_to, x0, y0);
388394 }
389395 queue_push (agg::path_cmd_line_to, x1, y1);
396+ if (closed && !m_was_clipped) {
397+ // Close the path only if the end point hasn't moved.
398+ queue_push (agg::path_cmd_end_poly | agg::path_flags_close,
399+ x1, y1);
400+ }
390401
391402 m_moveto = false ;
392403 return 1 ;
@@ -417,12 +428,23 @@ class PathClipper : public EmbeddedQueue<3>
417428 switch (code) {
418429 case (agg::path_cmd_end_poly | agg::path_flags_close):
419430 if (m_has_init) {
420- draw_clipped_line (m_lastX, m_lastY, m_initX, m_initY);
431+ // Queue the line from last point to the initial point, and
432+ // if never clipped, add a close code.
433+ draw_clipped_line (m_lastX, m_lastY, m_initX, m_initY,
434+ true );
435+ } else {
436+ // An empty path that is immediately closed.
437+ queue_push (
438+ agg::path_cmd_end_poly | agg::path_flags_close,
439+ m_lastX, m_lastY);
421440 }
422- queue_push (
423- agg::path_cmd_end_poly | agg::path_flags_close,
424- m_lastX, m_lastY);
425- goto exit_loop;
441+ // If paths were not clipped, then the above code queued
442+ // something, and we should exit the loop. Otherwise, continue
443+ // to the next point, as there may be a new subpath.
444+ if (queue_nonempty ()) {
445+ goto exit_loop;
446+ }
447+ break ;
426448
427449 case agg::path_cmd_move_to:
428450
@@ -444,6 +466,7 @@ class PathClipper : public EmbeddedQueue<3>
444466 m_initY = m_lastY = *y;
445467 m_has_init = true ;
446468 m_moveto = true ;
469+ m_was_clipped = false ;
447470 // if the last command was moveto exit the loop to emit the code
448471 if (emit_moveto) {
449472 goto exit_loop;
0 commit comments