[gtk: 1/2] revealer: Fix child size allocation at small scales



commit dc6fe091b9cffb6eb36a563982bf0899c7cbc981
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Feb 11 12:22:34 2020 +0100

    revealer: Fix child size allocation at small scales
    
    As pointed out in https://gitlab.gnome.org/GNOME/gtk/issues/1481
    and seen from critical warnings with swinging revealers in widget-factory
    there are some size allocation issues in GtkRevealer.
    
    What happens is that we request a size of the revealer itself
    based on the child natural size and the current stage of the transition
    by applying a scale to the natural size. We then round up to nearest
    int size. However, we want the widget to render as if it did get the
    natural size so we can transform it, rather than the scaled down size.
    For example, a label should not start ellipsizing in the animation.
    So we inverse the scale when allocating the child.
    
    Unfortunately, for very small scales the inversion of the scale can
    result in very large sizes, and for such scales we rounded up the
    requested size to 1, so we will be allocating huuuuge children.
    
    In order to avoid such issue we pick an arbitrary maximum upscale
    scale factor of 100. This means that in the case where the allocated
    size is 1 we never allocate the child at > 100 px. This means
    that in large downscaling cases we may run into the clipping issue
    described above. However, at these downscaling levels (100 times!)
    we're unlikely to notice much detail anyway.

 gtk/gtkrevealer.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)
---
diff --git a/gtk/gtkrevealer.c b/gtk/gtkrevealer.c
index 68e4eba828..0190cbb7a2 100644
--- a/gtk/gtkrevealer.c
+++ b/gtk/gtkrevealer.c
@@ -400,14 +400,36 @@ gtk_revealer_real_size_allocate (GtkWidget *widget,
       return;
     }
 
+  /* We request a different size than the child requested scaled by
+   * this scale as it will render smaller from the transision.
+   * However, we still want to allocate the child widget with its
+   * unscaled size so it renders right instead of e.g. ellipsizing or
+   * some other form of clipping. We do this by reverse-applying
+   * the scale when size allocating the child.
+   *
+   * Unfortunately this causes precision issues, because the scaled
+   * size request is always rounded up to an integer.  For instance if
+   * natural with is 100, and scale is 0.001.  we will request a
+   * natural size of ceil(0.1) == 1, but reversing this results in 1 /
+   * 0.001 == 1000 (rather than 100). In the swing case we can get the
+   * scale arbitrarily near 0 causing arbitrary large problems here.
+   *
+   * In order to avoid such issue we pick an arbitrary maximum upscale
+   * scale factor of 100. This means that in the case where the allocated
+   * size is 1 we never allocate the child at > 100 px. This means
+   * that in large downscaling cases we may run into the clipping issue
+   * described above. However, at these downscaling levels (100 times!)
+   * we're unlikely to notice much detail anyway.
+   */
+
   if (hscale < 1.0)
     {
       g_assert (vscale == 1.0);
-      child_width = MIN (G_MAXINT, ceil (width / hscale));
+      child_width = MIN (100*width, ceil (width / hscale));
     }
   else if (vscale < 1.0)
     {
-      child_height = MIN (G_MAXINT, ceil (height / vscale));
+      child_height = MIN (100*height, ceil (height / vscale));
     }
 
   transform = NULL;


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