>From 0910fb8e2dfb71c2dff44c6b99633ab61baa7f0e Mon Sep 17 00:00:00 2001 From: Po Lu Date: Fri, 17 Dec 2021 09:40:41 +0800 Subject: [PATCH 2/2] Allow window-text-pixel-size to measure from pixels above a position * doc/lispref/display.texi (Size of Displayed Text): Announce new meaning of `from'. * etc/NEWS: Announce changes. * lisp/pixel-scroll.el (pixel-scroll-precision-scroll-up-page): Use new feature. * src/xdisp.c (window_text_pixel_size): Understand a special format of `from' that specifies the amount of pixels above a position. (Fwindow_text_pixel_size): Update doc string. --- doc/lispref/display.texi | 20 ++++++++----- etc/NEWS | 3 ++ lisp/pixel-scroll.el | 34 +++++++++++---------- src/xdisp.c | 64 ++++++++++++++++++++++++++++++++-------- 4 files changed, 84 insertions(+), 37 deletions(-) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index bf0d1c05e1..766b2c5d64 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2090,19 +2090,23 @@ Size of Displayed Text This function returns the size of the text of @var{window}'s buffer in pixels. @var{window} must be a live window and defaults to the selected one. The return value is a cons of the maximum pixel-width -of any text line and the maximum pixel-height of all text lines. This -function exists to allow Lisp programs to adjust the dimensions of -@var{window} to the buffer text it needs to display. +of any text line and the maximum pixel-height of all text lines, or if +@var{from} is a cons, a list of the pixel-width, pixel-height, and the +buffer position of the first line that was measured. This function +exists to allow Lisp programs to adjust the dimensions of @var{window} +to the buffer text it needs to display. The optional argument @var{from}, if non-@code{nil}, specifies the first text position to consider, and defaults to the minimum accessible position of the buffer. If @var{from} is @code{t}, it stands for the minimum accessible position that is not a newline -character. The optional argument @var{to}, if non-@code{nil}, -specifies the last text position to consider, and defaults to the -maximum accessible position of the buffer. If @var{to} is @code{t}, -it stands for the maximum accessible position that is not a newline -character. +character. If @var{from} is a cons, the cdr specifies a position, and +the car specifies the minimum amount of pixels above that position to +start measuring from. The optional argument @var{to}, if +non-@code{nil}, specifies the last text position to consider, and +defaults to the maximum accessible position of the buffer. If +@var{to} is @code{t}, it stands for the maximum accessible position +that is not a newline character. The optional argument @var{x-limit}, if non-@code{nil}, specifies the maximum X coordinate beyond which text should be ignored; it is diff --git a/etc/NEWS b/etc/NEWS index b3e335f00a..47145adbc0 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -989,6 +989,9 @@ character. This controls whether or not the screen line at the end of the measured area will be counted during the height calculation. ++++ +** 'window-text-pixel-size' can now measure from a set amount of pixels above a position. + ** XDG support *** New function 'xdg-state-home' returns 'XDG_STATE_HOME' environment variable. diff --git a/lisp/pixel-scroll.el b/lisp/pixel-scroll.el index fa0185b16e..efcabae108 100644 --- a/lisp/pixel-scroll.el +++ b/lisp/pixel-scroll.el @@ -516,22 +516,24 @@ pixel-scroll-precision-scroll-up-page usable-height)))) (goto-char up-point))) (let ((current-vscroll (window-vscroll nil t))) - (if (<= delta current-vscroll) - (set-window-vscroll nil (- current-vscroll delta) t) - (setq delta (- delta current-vscroll)) - (set-window-vscroll nil 0 t) - (while (> delta 0) - (let ((position (pixel-point-and-height-at-unseen-line))) - (unless (cdr position) - (signal 'beginning-of-buffer nil)) - (set-window-start nil (car position) t) - ;; If the line above is taller than the window height (i.e. there's - ;; a very tall image), keep point on it. - (when (> (cdr position) usable-height) - (goto-char (car position))) - (setq delta (- delta (cdr position))))) - (when (< delta 0) - (set-window-vscroll nil (- delta) t)))))) + (setq delta (- delta current-vscroll)) + (set-window-vscroll nil 0 t) + (when (> delta 0) + (let* ((start (window-start)) + (dims (window-text-pixel-size nil (cons start delta) + start nil nil nil t)) + (height (nth 1 dims)) + (position (nth 2 dims))) + (set-window-start nil position t) + ;; If the line above is taller than the window height (i.e. there's + ;; a very tall image), keep point on it. + (when (> height usable-height) + (goto-char position)) + (when (or (not position) (eq position start)) + (signal 'beginning-of-buffer nil)) + (setq delta (- delta height)))) + (when (< delta 0) + (set-window-vscroll nil (- delta) t))))) (defun pixel-scroll-precision-interpolate (delta) "Interpolate a scroll of DELTA pixels. diff --git a/src/xdisp.c b/src/xdisp.c index 0772238f2d..e84f99499b 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -10840,7 +10840,8 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Li ptrdiff_t start, end, bpos; struct text_pos startp; void *itdata = NULL; - int c, max_x = 0, max_y = 0, x = 0, y = 0; + int c, max_x = 0, max_y = 0, x = 0, y = 0, movement = 0, doff; + bool saw_display_prop_at_end_p = false; if (NILP (from)) { @@ -10866,6 +10867,13 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Li break; } } + else if (CONSP (from)) + { + start = clip_to_bounds (BEGV, fix_position (XCAR (from)), ZV); + bpos = CHAR_TO_BYTE (start); + CHECK_FIXNAT (XCDR (from)); + movement = XFIXNAT (XCDR (from)); + } else { start = clip_to_bounds (BEGV, fix_position (from), ZV); @@ -10912,6 +10920,27 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Li itdata = bidi_shelve_cache (); start_display (&it, w, startp); + + if (movement > 0) + { + int last_y; + it.current_y = 0; + + move_it_by_lines (&it, 0); + + while (-it.current_y < movement) + { + last_y = it.current_y; + move_it_vertically_backward (&it, movement + it.current_y); + + if (it.current_y == last_y) + break; + } + + it.current_y = 0; + start = clip_to_bounds (BEGV, IT_CHARPOS (it), ZV); + } + int start_y = it.current_y; /* It makes no sense to measure dimensions of region of text that crosses the point where bidi reordering changes scan direction. @@ -11005,7 +11034,10 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Li y = (it.current_y + (NILP (no_ascents_descents) ? it.max_ascent + it.max_descent : 0) - - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w)); + - (movement < 0 + ? (WINDOW_TAB_LINE_HEIGHT (w) + - WINDOW_HEADER_LINE_HEIGHT (w)) + : 0)); if (saw_display_prop_at_end_p) y += doff; @@ -11053,26 +11085,32 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object from, Lisp_Object to, Li bidi_unshelve_cache (itdata, false); - return Fcons (make_fixnum (x - start_x), make_fixnum (y)); + return (!movement + ? Fcons (make_fixnum (x - start_x), make_fixnum (y)) + : list3i (x - start_x, y, start)); } DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_size, 0, 7, 0, - doc: /* Return the size of the text of WINDOW's buffer in pixels. -WINDOW must be a live window and defaults to the selected one. The -return value is a cons of the maximum pixel-width of any text line -and the pixel-height of all the text lines in the accessible portion -of buffer text. + doc: /* Return the size of the text of WINDOW's buffer in +pixels. WINDOW must be a live window and defaults to the selected +one. The return value is a cons of the maximum pixel-width of any +text line and the pixel-height of all the text lines in the accessible +portion of buffer text or a list of the maximum pixel-width, +pixel-height, and the buffer position of the line at FROM. This function exists to allow Lisp programs to adjust the dimensions of WINDOW to the buffer text it needs to display. The optional argument FROM, if non-nil, specifies the first text position to consider, and defaults to the minimum accessible position -of the buffer. If FROM is t, it stands for the minimum accessible -position that starts a non-empty line. TO, if non-nil, specifies the -last text position and defaults to the maximum accessible position of -the buffer. If TO is t, it stands for the maximum accessible position -that ends a non-empty line. +of the buffer. If FROM is a cons, the cdr specifies the amount of +pixels above the buffer position to begin measuring text, and the car +specifies the buffer position. In that case, a list is returned. If +FROM is t, it stands for the minimum accessible position that starts a +non-empty line. TO, if non-nil, specifies the last text position and +defaults to the maximum accessible position of the buffer. If TO is +t, it stands for the maximum accessible position that ends a non-empty +line. The optional argument X-LIMIT, if non-nil, specifies the maximum X coordinate beyond which the text should be ignored. It is therefore -- 2.33.1