Subject: Re: bug#37770: [PATCH] Expose scale factor through the redisplay interface

From: Carlos Pita <[email-masked]>
Date: Sun, 20 Oct 2019 14:22:10 -0300

> I'm not sure about this.  Admittedly, I'm not an expert on screen
> scales on GUI systems, but why do we need to drop the two scale
> factors as part of this change, which is basically just refactoring?
> I'd suggest to keep the 2 scale factors for now.  We can always
> replace 2 with one later.

I might do that, I might rename x/w32_get_scale_factor to
x/w32_get_scale_factor_xy and then define the rif exposed
x/w32_get_scale_factor to call these ones and simply drop the y scale
factor. But I would prefer not to do that because:

1. It adds complexity (more code, two different apis).

2. The only users of the (static) _xy variants would be x/w32_draw_underwave.

3. For me, it's hard to figure out why a screen would offer, say, x
resolution = 2 * 96dpi and y resolution = 3 * 96dpi (and surely we
could accommodate a humble underwave drawing routing if such a screen
happens to exist).

4. The nsterm backend also draws underwaves and doesn't use two
different scale factors (indeed, it doesn't use any scale factor at
all, nor the rest of this backend does).

5. AFAIK, the "toolkit industry" has long been using one number as THE
scale factor. Moreover, most of the time this number is just 1 or 2.

Regarding point 3, it's easier to imagine a screen with 1.99 and 2.01
x and y ratios that get respectively truncated down 1 and 2 x and y
scale factors. Now, the problem is not the different scale factors but
the way they were computed, and this is not solved at all by using 2
scale factors. Maybe we should use round instead of floor there.

I've modified the code comment and the message comment according to
your comments, Eli. I've also changed floor to round.

Best regards
--
Carlos
From 837006c732b7792f20d27a7c8825fa542f6c7607 Mon Sep 17 00:00:00 2001
From: memeplex <[email-masked]>
Date: Tue, 15 Oct 2019 19:14:03 -0300
Subject: [PATCH] Expose scale factor through the redisplay interface
 (Bug#37770)

Note 1: both x_get_scale_factor and w32_get_scale_factor computed
distinct scales for x and y by taking the ratio between effective
resolution in each direction and a standard 96 dpi resolution.  Since
this ratio is then truncated to an integer (the floor) it seems to me
that there is no sensible possibility that these two numbers
diverge. Moreover, modern toolkits report one number as scale factor
and we need a common interface here. For those reasons I'm arbitrarily
picking the horizontal scale factor as THE scale factor.

Note 2: I decided to let get_scale_factor return a double, even tough
factors currently in use are all integers AFAIK. This is in
anticipation of fractional scaling. I believe it's prudent to keep
the interface general in this regard.

* src/dispextern.h (redisplay_interface): Add get_scale_factor API.

* src/xterm.c (x_get_scale_factor): Consolidate with xg_get_scale (see
bug#37752) and export through the rif. Simplify scale inferring
logic (see note 1 above).

* src/w32term.c (w32_get_scale_factor): Likewise simplify logic and
add to the rif.

* src/nsterm.m (ns_get_scale_factor): Add a dummy implementation that
always return 1 to the rif, since there are no uses of any scale
factor here.
---
 src/dispextern.h |  3 +++
 src/nsterm.m     |  6 ++++++
 src/w32term.c    | 29 +++++++++++------------------
 src/xterm.c      | 41 ++++++++++++++++++-----------------------
 4 files changed, 38 insertions(+), 41 deletions(-)

diff --git a/src/dispextern.h b/src/dispextern.h
index 0615b16d71..b93e25f216 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2942,6 +2942,9 @@ reset_mouse_highlight (Mouse_HLInfo *hlinfo)
 
 #ifdef HAVE_WINDOW_SYSTEM
 
+  /* Return the scale factor for the screen containing frame F.  */
+  double (*get_scale_factor) (struct frame *f);
+
   /* Draw a fringe bitmap in window W of row ROW using parameters P.  */
   void (*draw_fringe_bitmap) (struct window *w, struct glyph_row *row,
                               struct draw_fringe_bitmap_params *p);
diff --git a/src/nsterm.m b/src/nsterm.m
index 5583c6105c..7b95b9e20b 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2957,6 +2957,11 @@ so some key presses (TAB) are swallowed by the system.  */
 
    ========================================================================== */
 
+static double
+ns_get_scale_factor (struct frame *f)
+{
+  return 1;  /* TODO do we need to do something else here?  */
+}
 
 extern int max_used_fringe_bitmap;
 static void
@@ -5087,6 +5092,7 @@ static Lisp_Object ns_string_to_lispmod (const char *s)
   gui_clear_window_mouse_face,
   gui_get_glyph_overhangs,
   gui_fix_overlapping_area,
+  ns_get_scale_factor,
   ns_draw_fringe_bitmap,
   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
   0, /* destroy_fringe_bitmap */
diff --git a/src/w32term.c b/src/w32term.c
index 9da0845836..fc2893f254 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -304,20 +304,16 @@ w32_restore_glyph_string_clip (struct glyph_string *s)
     }
 }
 
-static void
-w32_get_scale_factor(struct w32_display_info *dpyinfo, int *scale_x, int *scale_y)
+static double
+w32_get_scale_factor(struct frame *f)
 {
+  struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   const int base_res = 96;
 
-  *scale_x = *scale_y = 1;
-
-  if (dpyinfo)
-    {
-      if (dpyinfo->resx > base_res)
-	*scale_x = floor (dpyinfo->resx / base_res);
-      if (dpyinfo->resy > base_res)
-	*scale_y = floor (dpyinfo->resy / base_res);
-    }
+  if (dpyinfo && dpyinfo->resx > base_res)
+    return round (dpyinfo->resx / base_res);
+  else
+    return 1;
 }
 
 /*
@@ -334,12 +330,8 @@ w32_get_scale_factor(struct w32_display_info *dpyinfo, int *scale_x, int *scale_
 static void
 w32_draw_underwave (struct glyph_string *s, COLORREF color)
 {
-  struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
-
-  int scale_x, scale_y;
-  w32_get_scale_factor (dpyinfo, &scale_x, &scale_y);
-
-  int wave_height = 3 * scale_y, wave_length = 2 * scale_x, thickness = scale_y;
+  double scale = w32_get_scale_factor (s->f);
+  int wave_height = 3 * scale, wave_length = 2 * scale, thickness = scale;
   int dx, dy, x0, y0, width, x1, y1, x2, y2, odd, xmax;
   Emacs_Rectangle wave_clip, string_clip, final_clip;
   RECT w32_final_clip, w32_string_clip;
@@ -348,7 +340,7 @@ w32_draw_underwave (struct glyph_string *s, COLORREF color)
   dx = wave_length;
   dy = wave_height - 1;
   x0 = s->x;
-  y0 = s->ybase + wave_height / 2 - scale_y;
+  y0 = s->ybase + wave_height / 2 - scale;
   width = s->width;
   xmax = x0 + width;
 
@@ -7192,6 +7184,7 @@ w32_make_rdb (char *xrm_option)
   gui_clear_window_mouse_face,
   gui_get_glyph_overhangs,
   gui_fix_overlapping_area,
+  w32_get_scale_factor,
   w32_draw_fringe_bitmap,
   w32_define_fringe_bitmap,
   w32_destroy_fringe_bitmap,
diff --git a/src/xterm.c b/src/xterm.c
index 045589534f..1a5c339fa7 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -3611,21 +3611,21 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
   s->background_filled_p = true;
 }
 
-static void
-x_get_scale_factor(Display *disp, int *scale_x, int *scale_y)
+static double
+x_get_scale_factor(struct frame *f)
 {
+#ifdef USE_GTK
+  return xg_get_scale (f);
+#else
+  Display *disp = FRAME_X_DISPLAY (f);
+  struct x_display_info *dpyinfo = x_display_info_for_display (disp);
   const int base_res = 96;
-  struct x_display_info * dpyinfo = x_display_info_for_display (disp);
-
-  *scale_x = *scale_y = 1;
 
-  if (dpyinfo)
-    {
-      if (dpyinfo->resx > base_res)
-	*scale_x = floor (dpyinfo->resx / base_res);
-      if (dpyinfo->resy > base_res)
-	*scale_y = floor (dpyinfo->resy / base_res);
-    }
+  if (dpyinfo && dpyinfo->resx > base_res)
+    return round (dpyinfo->resx / base_res);
+  else
+    return 1;
+#endif /* USE_GTK */
 }
 
 /*
@@ -3641,27 +3641,21 @@ x_get_scale_factor(Display *disp, int *scale_x, int *scale_y)
 static void
 x_draw_underwave (struct glyph_string *s)
 {
-  Display *display = FRAME_X_DISPLAY (s->f);
-
   /* Adjust for scale/HiDPI.  */
-  int scale_x, scale_y;
-
-  x_get_scale_factor (display, &scale_x, &scale_y);
-
-  int wave_height = 3 * scale_y, wave_length = 2 * scale_x;
-
+  double scale = x_get_scale_factor (s->f);
+  int wave_height = 3 * scale, wave_length = 2 * scale;
 #ifdef USE_CAIRO
   x_draw_horizontal_wave (s->f, s->gc, s->x, s->ybase - wave_height + 3,
 			  s->width, wave_height, wave_length);
 #else  /* not USE_CAIRO */
-  int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax, thickness = scale_y;;
+  int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax, thickness = scale;
   bool odd;
   XRectangle wave_clip, string_clip, final_clip;
 
   dx = wave_length;
   dy = wave_height - 1;
   x0 = s->x;
-  y0 = s->ybase + wave_height / 2 - scale_y;
+  y0 = s->ybase + wave_height / 2 - scale;
   width = s->width;
   xmax = x0 + width;
 
@@ -10557,7 +10551,7 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_
 {
   int modified_top, modified_left;
 #ifdef USE_GTK
-  int scale = xg_get_scale (f);
+  double scale = x_get_scale_factor (f);
 #endif
 
   if (change_gravity > 0)
@@ -13357,6 +13351,7 @@ x_activate_timeout_atimer (void)
     gui_clear_window_mouse_face,
     gui_get_glyph_overhangs,
     gui_fix_overlapping_area,
+    x_get_scale_factor,
     x_draw_fringe_bitmap,
 #ifdef USE_CAIRO
     x_cr_define_fringe_bitmap,
-- 
2.20.1