Below is an updated version of the patch with entries in etc/NEWS and a fix for a typo in the doc-string of `default-font-height'. The old ChangeLog entry can be reused: Implement functions for measuring fonts and max chars per line * simple.el (default-font-width): new function. * (default-font-height): elaborate doc-string * window.el (window-font-width): new function (window-font-height): new function (window-max-chars-per-line): new function diff --git a/etc/NEWS b/etc/NEWS index 14a9176..4adcb3d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -163,6 +163,24 @@ possible inaccuracies in the end position. In particular, it now returns the average width of the font's characters, which can be used for geometry-related calculations. +** A new function `default-font-width' returns the average width of a +character in the current buffer's default font. If the default face +is remapped (see `face-remapping-alist'), the value for the remapped +face is returned. This function complements the existing function +`default-font-height'. + +** New functions `window-font-height' and `window-font-width return +the height and average width of characters in a specified face and +window. If FACE is remapped (see `face-remapping-alist'), the +function returns the information for the remapped face. + +** A new function `window-max-chars-per-line' returns the maximal +number of characters that can be displayed on one line. If a face +and/or window are provided, these values are used for the +calculation. This function is different from `window-body-width' in +that it accounts for (i) continuation glyphs, (ii) the size of the +font, and (iii) the specified window. + * Editing Changes in Emacs 25.1 diff --git a/lisp/simple.el b/lisp/simple.el index 0fcd5db..b700c68 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -5377,7 +5377,10 @@ lines." (declare-function font-info "font.c" (name &optional frame)) (defun default-font-height () - "Return the height in pixels of the current buffer's default face font." + "Return the height in pixels of the current buffer's default face font. + +If the default font is remapped (see `face-remapping-alist'), the +function returns the height of the remapped face." (let ((default-font (face-font 'default))) (cond ((and (display-multi-font-p) @@ -5388,6 +5391,25 @@ lines." (aref (font-info default-font) 3)) (t (frame-char-height))))) +(defun default-font-width () + "Return the width in pixels of the current buffer's default face font. + +If the default font is remapped (see `face-remapping-alist'), the +function returns the width of the remapped face." + (let ((default-font (face-font 'default))) + (cond + ((and (display-multi-font-p) + ;; Avoid calling font-info if the frame's default font was + ;; not changed since the frame was created. That's because + ;; font-info is expensive for some fonts, see bug #14838. + (not (string= (frame-parameter nil 'font) default-font))) + (let* ((info (font-info (face-font 'default))) + (width (aref info 11))) + (if (> width 0) + width + (aref info 10)))) + (t (frame-char-width))))) + (defun default-line-height () "Return the pixel height of current buffer's default-face text line. diff --git a/lisp/window.el b/lisp/window.el index c95b0d6..990f953 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -1830,6 +1830,57 @@ optional argument PIXELWISE is passed to the functions." (window-body-width window pixelwise) (window-body-height window pixelwise))) +(defun window-font-width (&optional window face) + "Return average character width for the font of FACE used in WINDOW. +WINDOW must be a live window and defaults to the selected one. + +If FACE is nil or omitted, the default face is used. If FACE is +remapped (see `face-remapping-alist'), the function returns the +information for the remapped face." + (with-selected-window (window-normalize-window window t) + (let* ((face (if face face 'default)) + (info (font-info (face-font face))) + (width (aref info 11))) + (if (> width 0) + width + (aref info 10))))) + +(defun window-font-height (&optional window face) + "Return character height for the font of FACE used in WINDOW. +WINDOW must be a live window and defaults to the selected one. + +If FACE is nil or omitted, the default face is used. If FACE is +remapped (see `face-remapping-alist'), the function returns the +information for the remapped face." + (with-selected-window (window-normalize-window window t) + (let* ((face (if face face 'default)) + (info (font-info (face-font face)))) + (aref info 3)))) + +(defun window-max-chars-per-line (&optional window face) + "Return the number of characters that can be displayed on one line in WINDOW. +WINDOW must be a live window and defaults to the selected one. + +The character width of FACE is used for the calculation. If FACE +is nil or omitted, the default face is used. If FACE is +remapped (see `face-remapping-alist'), the function uses the +remapped face. + +This function is different from `window-body-width' in two +ways. First, it accounts for the portions of the line reserved +for the continuation glyph. Second, it accounts for the size of +the font." + (with-selected-window (window-normalize-window window t) + (let* ((window-width (window-body-width window t)) + (font-width (window-font-width window face)) + (ncols (/ window-width font-width))) + (if (and (display-graphic-p) + overflow-newline-into-fringe + (/= (frame-parameter nil 'left-fringe) 0) + (/= (frame-parameter nil 'right-fringe) 0)) + ncols + (1- ncols))))) + (defun window-current-scroll-bars (&optional window) "Return the current scroll bar types for WINDOW. WINDOW must be a live window and defaults to the selected one.