Subject: Re: bug#23259: 25.1.50; Xerror: "BadLength" on extreme zoom causing emacs to segfault

From: Eli Zaretskii <[email-masked]>
Date: Sun, 10 Apr 2016 19:24:00 +0300

> From: Matthew Leach <[email-masked]>
> Cc: [email-masked]
> Date: Sun, 10 Apr 2016 16:33:17 +0100
> 
> Maybe limit the zoom before X would crash?  Presumably X has an upper
> bound on how large it can render things since it can yield a BadLength
> error.  However, I've never studied X before.

I think we can use the display dimensions instead: it makes little
sense to make the font larger than that.

> >   . what is the maximum value of the scale factor you see on the mode
> >     line before Emacs crashes
> 
> I can get to about +34 before it crashes.
> 
> >   . what is the value returned by display-pixel-width
> 
> (display-pixel-width) => 1366
> 
> >   . what is the values returned by frame-char-width and
> >     frame-char-height
> 
> (frame-char-width) => 9
> (frame-char-height) => 18

Thanks.  Please try the patch below.  It should also avoid similar
crashes when you repeatedly press C-- to decrease the font.

--- lisp/face-remap.el~0	2016-01-03 06:46:29.000000000 +0200
+++ lisp/face-remap.el	2016-04-10 16:03:57.601223100 +0300
@@ -256,6 +256,14 @@
 						text-scale-mode-amount))))
   (force-window-update (current-buffer)))
 
+(defun text-scale-min-amount ()
+  "Return the minimum amount of text-scaling we allow."
+  (log (/ 1.0 (frame-char-height)) text-scale-mode-step))
+
+(defun text-scale-max-amount ()
+  "Return the maximum amount of text-scaling we allow."
+  (log (/ (min (display-pixel-width) #xffff) (frame-char-width)) text-scale-mode-step))
+
 ;;;###autoload
 (defun text-scale-set (level)
   "Set the scale factor of the default face in the current buffer to LEVEL.
@@ -266,7 +274,8 @@
 `text-scale-mode-step' (a negative number decreases the height by
 the same amount)."
   (interactive "p")
-  (setq text-scale-mode-amount level)
+  (setq text-scale-mode-amount
+        (max (min level (text-scale-max-amount)) (text-scale-min-amount)))
   (text-scale-mode (if (zerop text-scale-mode-amount) -1 1)))
 
 ;;;###autoload
@@ -279,8 +288,13 @@
 height by the same amount).  As a special case, an argument of 0
 will remove any scaling currently active."
   (interactive "p")
-  (setq text-scale-mode-amount
-	(if (= inc 0) 0 (+ (if text-scale-mode text-scale-mode-amount 0) inc)))
+  (let* ((current-value (if text-scale-mode text-scale-mode-amount 0))
+         (new-value (if (= inc 0) 0 (+ current-value inc))))
+    (if (or (> new-value (text-scale-max-amount))
+            (< new-value (text-scale-min-amount)))
+        (user-error "Cannot %s the default face height more than it already is"
+                    (if (> inc 0) "increase" "decrease")))
+    (setq text-scale-mode-amount new-value))
   (text-scale-mode (if (zerop text-scale-mode-amount) -1 1)))
 
 ;;;###autoload