[gimp] Bug 791741 - Transparent rectangles when image is drawn



commit 231578411013e3009d6793d95ae2d742c8166cea
Author: Ell <ell_se yahoo com>
Date:   Tue Dec 19 14:42:28 2017 -0500

    Bug 791741 - Transparent rectangles when image is drawn
    
    Add gimp_display_shell_[un]transform_with_scale(), which are
    similar to gimp_display_shell_[un]transform(), however, they
    transform the bounding box to/from uniformly-scaled image space,
    given the scale factor as a parameter.  These functions are more
    accurate than using gimp_display_shell_[un]transform() and applying
    the scaling separately, in particular, when the scale matches the
    (horizontal or vertical) display scale.
    
    Use these functions in gimp_display_shell_draw_image(), to avoid an
    off-by-one error when transforming screen-space chunks to image-
    space chunks, which leads to the symptoms described in the bug.
    
    Fix another potential off-by-one error affecting non-uniformly
    scaled images, and window scale factors other than 1.

 app/display/gimpdisplayshell-draw.c      |   29 ++--
 app/display/gimpdisplayshell-transform.c |   86 +++++++++
 app/display/gimpdisplayshell-transform.h |  295 ++++++++++++++++--------------
 3 files changed, 260 insertions(+), 150 deletions(-)
---
diff --git a/app/display/gimpdisplayshell-draw.c b/app/display/gimpdisplayshell-draw.c
index c696775..372f275 100644
--- a/app/display/gimpdisplayshell-draw.c
+++ b/app/display/gimpdisplayshell-draw.c
@@ -166,11 +166,13 @@ gimp_display_shell_draw_image (GimpDisplayShell *shell,
       gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (shell))));
 #endif
 
-  scale = MIN (scale, GIMP_DISPLAY_RENDER_MAX_SCALE);
+  scale  = MIN (scale, GIMP_DISPLAY_RENDER_MAX_SCALE);
+  scale *= MAX (shell->scale_x, shell->scale_y);
 
-  scale        *= MAX (shell->scale_x, shell->scale_y);
-  chunk_width  *= shell->scale_x / scale;
-  chunk_height *= shell->scale_y / scale;
+  if (scale != shell->scale_x)
+    chunk_width  = (chunk_width  - 1.0) * (shell->scale_x / scale);
+  if (scale != shell->scale_y)
+    chunk_height = (chunk_height - 1.0) * (shell->scale_y / scale);
 
   if (shell->rotate_untransform)
     {
@@ -198,15 +200,16 @@ gimp_display_shell_draw_image (GimpDisplayShell *shell,
           gint    ix, iy;
           gint    iw, ih;
 
-          /* map chunk from screen space to image space */
-          gimp_display_shell_untransform_bounds (shell,
-                                                 x1,   y1,   x2,   y2,
-                                                 &ix1, &iy1, &ix2, &iy2);
+          /* map chunk from screen space to scaled image space */
+          gimp_display_shell_untransform_bounds_with_scale (
+            shell, scale,
+            x1,   y1,   x2,   y2,
+            &ix1, &iy1, &ix2, &iy2);
 
-          ix = floor (ix1 * scale);
-          iy = floor (iy1 * scale);
-          iw = ceil  (ix2 * scale) - ix;
-          ih = ceil  (iy2 * scale) - iy;
+          ix = floor (ix1);
+          iy = floor (iy1);
+          iw = ceil  (ix2) - ix;
+          ih = ceil  (iy2) - iy;
 
           cairo_save (cr);
 
@@ -214,7 +217,7 @@ gimp_display_shell_draw_image (GimpDisplayShell *shell,
           cairo_rectangle (cr, x1, y1, x2 - x1, y2 - y1);
           cairo_clip (cr);
 
-          /* transform to image space, and apply uneven scaling */
+          /* transform to scaled image space, and apply uneven scaling */
           if (shell->rotate_transform)
             cairo_transform (cr, shell->rotate_transform);
           cairo_translate (cr, -shell->offset_x, -shell->offset_y);
diff --git a/app/display/gimpdisplayshell-transform.c b/app/display/gimpdisplayshell-transform.c
index a247a94..84918ab 100644
--- a/app/display/gimpdisplayshell-transform.c
+++ b/app/display/gimpdisplayshell-transform.c
@@ -863,6 +863,92 @@ gimp_display_shell_untransform_bounds (GimpDisplayShell *shell,
     }
 }
 
+/* transforms a bounding box from image-space, uniformly scaled by a factor of
+ * 'scale', to display-space.  this is equivalent to, but more accurate than,
+ * dividing the input by 'scale', and using
+ * gimp_display_shell_transform_bounds(), in particular, in that if 'scale'
+ * equals 'shell->scale_x' or 'shell->scale_y', there is no loss in accuracy
+ * in the corresponding dimension due to scaling (although there might be loss
+ * of accuracy due to rotation or translation.)
+ */
+void
+gimp_display_shell_transform_bounds_with_scale (GimpDisplayShell *shell,
+                                                gdouble           scale,
+                                                gdouble           x1,
+                                                gdouble           y1,
+                                                gdouble           x2,
+                                                gdouble           y2,
+                                                gdouble          *nx1,
+                                                gdouble          *ny1,
+                                                gdouble          *nx2,
+                                                gdouble          *ny2)
+{
+  gdouble factor_x;
+  gdouble factor_y;
+
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+  g_return_if_fail (scale > 0.0);
+  g_return_if_fail (nx1 != NULL);
+  g_return_if_fail (ny1 != NULL);
+  g_return_if_fail (nx2 != NULL);
+  g_return_if_fail (ny2 != NULL);
+
+  factor_x = shell->scale_x / scale;
+  factor_y = shell->scale_y / scale;
+
+  x1 = x1 * factor_x - shell->offset_x;
+  y1 = y1 * factor_y - shell->offset_y;
+  x2 = x2 * factor_x - shell->offset_x;
+  y2 = y2 * factor_y - shell->offset_y;
+
+  gimp_display_shell_rotate_bounds (shell,
+                                    x1,  y1,  x2,  y2,
+                                    nx1, ny1, nx2, ny2);
+}
+
+/* transforms a bounding box from display-space to image-space, uniformly
+ * scaled by a factor of 'scale'.  this is equivalent to, but more accurate
+ * than, using gimp_display_shell_untransform_bounds(), and multiplying the
+ * output by 'scale', in particular, in that if 'scale' equals 'shell->scale_x'
+ * or 'shell->scale_y', there is no loss in accuracy in the corresponding
+ * dimension due to scaling (although there might be loss of accuracy due to
+ * rotation or translation.)
+ */
+void
+gimp_display_shell_untransform_bounds_with_scale (GimpDisplayShell *shell,
+                                                  gdouble           scale,
+                                                  gdouble           x1,
+                                                  gdouble           y1,
+                                                  gdouble           x2,
+                                                  gdouble           y2,
+                                                  gdouble          *nx1,
+                                                  gdouble          *ny1,
+                                                  gdouble          *nx2,
+                                                  gdouble          *ny2)
+{
+  gdouble factor_x;
+  gdouble factor_y;
+
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+  g_return_if_fail (scale > 0.0);
+  g_return_if_fail (nx1 != NULL);
+  g_return_if_fail (ny1 != NULL);
+  g_return_if_fail (nx2 != NULL);
+  g_return_if_fail (ny2 != NULL);
+
+  factor_x = scale / shell->scale_x;
+  factor_y = scale / shell->scale_y;
+
+  gimp_display_shell_unrotate_bounds (shell,
+                                      x1,  y1,  x2,  y2,
+                                      nx1, ny1, nx2, ny2);
+
+  *nx1 = (*nx1 + shell->offset_x) * factor_x;
+  *ny1 = (*ny1 + shell->offset_y) * factor_y;
+  *nx2 = (*nx2 + shell->offset_x) * factor_x;
+  *ny2 = (*ny2 + shell->offset_y) * factor_y;
+}
+
 /**
  * gimp_display_shell_untransform_viewport:
  * @shell:  a #GimpDisplayShell
diff --git a/app/display/gimpdisplayshell-transform.h b/app/display/gimpdisplayshell-transform.h
index 8d5bd6b..9b6a1a0 100644
--- a/app/display/gimpdisplayshell-transform.h
+++ b/app/display/gimpdisplayshell-transform.h
@@ -23,95 +23,95 @@
  *  space and back, taking into account scroll offset and scale
  */
 
-void  gimp_display_shell_zoom_coords          (GimpDisplayShell   *shell,
-                                               const GimpCoords   *image_coords,
-                                               GimpCoords         *display_coords);
-void  gimp_display_shell_unzoom_coords        (GimpDisplayShell   *shell,
-                                               const GimpCoords   *display_coords,
-                                               GimpCoords         *image_coords);
-
-void  gimp_display_shell_zoom_xy              (GimpDisplayShell   *shell,
-                                               gdouble             x,
-                                               gdouble             y,
-                                               gint               *nx,
-                                               gint               *ny);
-void  gimp_display_shell_unzoom_xy            (GimpDisplayShell   *shell,
-                                               gint                x,
-                                               gint                y,
-                                               gint               *nx,
-                                               gint               *ny,
-                                               gboolean            round);
-
-void  gimp_display_shell_zoom_xy_f            (GimpDisplayShell   *shell,
-                                               gdouble             x,
-                                               gdouble             y,
-                                               gdouble            *nx,
-                                               gdouble            *ny);
-void  gimp_display_shell_unzoom_xy_f          (GimpDisplayShell   *shell,
-                                               gdouble             x,
-                                               gdouble             y,
-                                               gdouble            *nx,
-                                               gdouble            *ny);
-
-void  gimp_display_shell_zoom_segments        (GimpDisplayShell   *shell,
-                                               const GimpBoundSeg *src_segs,
-                                               GimpSegment        *dest_segs,
-                                               gint                n_segs,
-                                               gdouble             offset_x,
-                                               gdouble             offset_y);
+void  gimp_display_shell_zoom_coords                   (GimpDisplayShell   *shell,
+                                                        const GimpCoords   *image_coords,
+                                                        GimpCoords         *display_coords);
+void  gimp_display_shell_unzoom_coords                 (GimpDisplayShell   *shell,
+                                                        const GimpCoords   *display_coords,
+                                                        GimpCoords         *image_coords);
+
+void  gimp_display_shell_zoom_xy                       (GimpDisplayShell   *shell,
+                                                        gdouble             x,
+                                                        gdouble             y,
+                                                        gint               *nx,
+                                                        gint               *ny);
+void  gimp_display_shell_unzoom_xy                     (GimpDisplayShell   *shell,
+                                                        gint                x,
+                                                        gint                y,
+                                                        gint               *nx,
+                                                        gint               *ny,
+                                                        gboolean            round);
+
+void  gimp_display_shell_zoom_xy_f                     (GimpDisplayShell   *shell,
+                                                        gdouble             x,
+                                                        gdouble             y,
+                                                        gdouble            *nx,
+                                                        gdouble            *ny);
+void  gimp_display_shell_unzoom_xy_f                   (GimpDisplayShell   *shell,
+                                                        gdouble             x,
+                                                        gdouble             y,
+                                                        gdouble            *nx,
+                                                        gdouble            *ny);
+
+void  gimp_display_shell_zoom_segments                 (GimpDisplayShell   *shell,
+                                                        const GimpBoundSeg *src_segs,
+                                                        GimpSegment        *dest_segs,
+                                                        gint                n_segs,
+                                                        gdouble             offset_x,
+                                                        gdouble             offset_y);
 
 
 /*  rotate: functions to transform from unrotated and unflipped but
  *  zoomed display space to rotated and filpped display space and back
  */
 
-void  gimp_display_shell_rotate_coords        (GimpDisplayShell   *shell,
-                                               const GimpCoords   *image_coords,
-                                               GimpCoords         *display_coords);
-void  gimp_display_shell_unrotate_coords      (GimpDisplayShell   *shell,
-                                               const GimpCoords   *display_coords,
-                                               GimpCoords         *image_coords);
-
-void  gimp_display_shell_rotate_xy            (GimpDisplayShell   *shell,
-                                               gdouble             x,
-                                               gdouble             y,
-                                               gint               *nx,
-                                               gint               *ny);
-void  gimp_display_shell_unrotate_xy          (GimpDisplayShell   *shell,
-                                               gint                x,
-                                               gint                y,
-                                               gint               *nx,
-                                               gint               *ny);
-
-void  gimp_display_shell_rotate_xy_f          (GimpDisplayShell   *shell,
-                                               gdouble             x,
-                                               gdouble             y,
-                                               gdouble            *nx,
-                                               gdouble            *ny);
-void  gimp_display_shell_unrotate_xy_f        (GimpDisplayShell   *shell,
-                                               gdouble             x,
-                                               gdouble             y,
-                                               gdouble            *nx,
-                                               gdouble            *ny);
-
-void  gimp_display_shell_rotate_bounds        (GimpDisplayShell   *shell,
-                                               gdouble             x1,
-                                               gdouble             y1,
-                                               gdouble             x2,
-                                               gdouble             y2,
-                                               gdouble            *nx1,
-                                               gdouble            *ny1,
-                                               gdouble            *nx2,
-                                               gdouble            *ny2);
-void  gimp_display_shell_unrotate_bounds      (GimpDisplayShell   *shell,
-                                               gdouble             x1,
-                                               gdouble             y1,
-                                               gdouble             x2,
-                                               gdouble             y2,
-                                               gdouble            *nx1,
-                                               gdouble            *ny1,
-                                               gdouble            *nx2,
-                                               gdouble            *ny2);
+void  gimp_display_shell_rotate_coords                 (GimpDisplayShell   *shell,
+                                                        const GimpCoords   *image_coords,
+                                                        GimpCoords         *display_coords);
+void  gimp_display_shell_unrotate_coords               (GimpDisplayShell   *shell,
+                                                        const GimpCoords   *display_coords,
+                                                        GimpCoords         *image_coords);
+
+void  gimp_display_shell_rotate_xy                     (GimpDisplayShell   *shell,
+                                                        gdouble             x,
+                                                        gdouble             y,
+                                                        gint               *nx,
+                                                        gint               *ny);
+void  gimp_display_shell_unrotate_xy                   (GimpDisplayShell   *shell,
+                                                        gint                x,
+                                                        gint                y,
+                                                        gint               *nx,
+                                                        gint               *ny);
+
+void  gimp_display_shell_rotate_xy_f                   (GimpDisplayShell   *shell,
+                                                        gdouble             x,
+                                                        gdouble             y,
+                                                        gdouble            *nx,
+                                                        gdouble            *ny);
+void  gimp_display_shell_unrotate_xy_f                 (GimpDisplayShell   *shell,
+                                                        gdouble             x,
+                                                        gdouble             y,
+                                                        gdouble            *nx,
+                                                        gdouble            *ny);
+
+void  gimp_display_shell_rotate_bounds                 (GimpDisplayShell   *shell,
+                                                        gdouble             x1,
+                                                        gdouble             y1,
+                                                        gdouble             x2,
+                                                        gdouble             y2,
+                                                        gdouble            *nx1,
+                                                        gdouble            *ny1,
+                                                        gdouble            *nx2,
+                                                        gdouble            *ny2);
+void  gimp_display_shell_unrotate_bounds               (GimpDisplayShell   *shell,
+                                                        gdouble             x1,
+                                                        gdouble             y1,
+                                                        gdouble             x2,
+                                                        gdouble             y2,
+                                                        gdouble            *nx1,
+                                                        gdouble            *ny1,
+                                                        gdouble            *nx2,
+                                                        gdouble            *ny2);
 
 
 /*  transform: functions to transform from image space to rotated
@@ -119,60 +119,81 @@ void  gimp_display_shell_unrotate_bounds      (GimpDisplayShell   *shell,
  *  rotation and flipping
  */
 
-void  gimp_display_shell_transform_coords     (GimpDisplayShell   *shell,
-                                               const GimpCoords   *image_coords,
-                                               GimpCoords         *display_coords);
-void  gimp_display_shell_untransform_coords   (GimpDisplayShell   *shell,
-                                               const GimpCoords   *display_coords,
-                                               GimpCoords         *image_coords);
-
-void  gimp_display_shell_transform_xy         (GimpDisplayShell   *shell,
-                                               gdouble             x,
-                                               gdouble             y,
-                                               gint               *nx,
-                                               gint               *ny);
-void  gimp_display_shell_untransform_xy       (GimpDisplayShell   *shell,
-                                               gint                x,
-                                               gint                y,
-                                               gint               *nx,
-                                               gint               *ny,
-                                               gboolean            round);
-
-void  gimp_display_shell_transform_xy_f       (GimpDisplayShell   *shell,
-                                               gdouble             x,
-                                               gdouble             y,
-                                               gdouble            *nx,
-                                               gdouble            *ny);
-void  gimp_display_shell_untransform_xy_f     (GimpDisplayShell   *shell,
-                                               gdouble             x,
-                                               gdouble             y,
-                                               gdouble            *nx,
-                                               gdouble            *ny);
-
-void  gimp_display_shell_transform_bounds     (GimpDisplayShell   *shell,
-                                               gdouble             x1,
-                                               gdouble             y1,
-                                               gdouble             x2,
-                                               gdouble             y2,
-                                               gdouble            *nx1,
-                                               gdouble            *ny1,
-                                               gdouble            *nx2,
-                                               gdouble            *ny2);
-void  gimp_display_shell_untransform_bounds   (GimpDisplayShell   *shell,
-                                               gdouble             x1,
-                                               gdouble             y1,
-                                               gdouble             x2,
-                                               gdouble             y2,
-                                               gdouble            *nx1,
-                                               gdouble            *ny1,
-                                               gdouble            *nx2,
-                                               gdouble            *ny2);
-
-void  gimp_display_shell_untransform_viewport (GimpDisplayShell   *shell,
-                                               gint               *x,
-                                               gint               *y,
-                                               gint               *width,
-                                               gint               *height);
+void  gimp_display_shell_transform_coords              (GimpDisplayShell   *shell,
+                                                        const GimpCoords   *image_coords,
+                                                        GimpCoords         *display_coords);
+void  gimp_display_shell_untransform_coords            (GimpDisplayShell   *shell,
+                                                        const GimpCoords   *display_coords,
+                                                        GimpCoords         *image_coords);
+
+void  gimp_display_shell_transform_xy                  (GimpDisplayShell   *shell,
+                                                        gdouble             x,
+                                                        gdouble             y,
+                                                        gint               *nx,
+                                                        gint               *ny);
+void  gimp_display_shell_untransform_xy                (GimpDisplayShell   *shell,
+                                                        gint                x,
+                                                        gint                y,
+                                                        gint               *nx,
+                                                        gint               *ny,
+                                                        gboolean            round);
+
+void  gimp_display_shell_transform_xy_f                (GimpDisplayShell   *shell,
+                                                        gdouble             x,
+                                                        gdouble             y,
+                                                        gdouble            *nx,
+                                                        gdouble            *ny);
+void  gimp_display_shell_untransform_xy_f              (GimpDisplayShell   *shell,
+                                                        gdouble             x,
+                                                        gdouble             y,
+                                                        gdouble            *nx,
+                                                        gdouble            *ny);
+
+void  gimp_display_shell_transform_bounds              (GimpDisplayShell   *shell,
+                                                        gdouble             x1,
+                                                        gdouble             y1,
+                                                        gdouble             x2,
+                                                        gdouble             y2,
+                                                        gdouble            *nx1,
+                                                        gdouble            *ny1,
+                                                        gdouble            *nx2,
+                                                        gdouble            *ny2);
+void  gimp_display_shell_untransform_bounds            (GimpDisplayShell   *shell,
+                                                        gdouble             x1,
+                                                        gdouble             y1,
+                                                        gdouble             x2,
+                                                        gdouble             y2,
+                                                        gdouble            *nx1,
+                                                        gdouble            *ny1,
+                                                        gdouble            *nx2,
+                                                        gdouble            *ny2);
+
+void  gimp_display_shell_transform_bounds_with_scale   (GimpDisplayShell   *shell,
+                                                        gdouble             scale,
+                                                        gdouble             x1,
+                                                        gdouble             y1,
+                                                        gdouble             x2,
+                                                        gdouble             y2,
+                                                        gdouble            *nx1,
+                                                        gdouble            *ny1,
+                                                        gdouble            *nx2,
+                                                        gdouble            *ny2);
+void  gimp_display_shell_untransform_bounds_with_scale (GimpDisplayShell   *shell,
+                                                        gdouble             scale,
+                                                        gdouble             x1,
+                                                        gdouble             y1,
+                                                        gdouble             x2,
+                                                        gdouble             y2,
+                                                        gdouble            *nx1,
+                                                        gdouble            *ny1,
+                                                        gdouble            *nx2,
+                                                        gdouble            *ny2);
+
+void  gimp_display_shell_untransform_viewport          (GimpDisplayShell   *shell,
+                                                        gint               *x,
+                                                        gint               *y,
+                                                        gint               *width,
+                                                        gint               *height);
 
 
 #endif /* __GIMP_DISPLAY_SHELL_TRANSFORM_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]