diff options
| author | Andreas Politz <politza@hochschule-trier.de> | 2014-11-14 10:06:26 +0100 |
|---|---|---|
| committer | Andreas Politz <politza@hochschule-trier.de> | 2014-11-14 10:06:26 +0100 |
| commit | cf7553e95d4eb7a04b1b418e4dc06c7654eb786b (patch) | |
| tree | 5360c3b73a7eda32a1226d68b3bfd2425f39c60c /lisp | |
| parent | 80ee4236f1d06a9b96a3ce7594f37e10c5227275 (diff) | |
*** empty log message ***
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/pdf-annot.el | 2 | ||||
| -rw-r--r-- | lisp/pdf-info.el | 5 | ||||
| -rw-r--r-- | lisp/pdf-isearch.el | 468 | ||||
| -rw-r--r-- | lisp/pdf-util.el | 1187 | ||||
| -rw-r--r-- | lisp/pdf-view.el | 75 |
5 files changed, 720 insertions, 1017 deletions
diff --git a/lisp/pdf-annot.el b/lisp/pdf-annot.el index 80f5f70..262f90d 100644 --- a/lisp/pdf-annot.el +++ b/lisp/pdf-annot.el @@ -1318,7 +1318,7 @@ i.e. a non mouse-movement event is read." buffer '(nil (inhibit-same-window . t)))) (when (pdf-util-page-displayed-p) - (pdf-util-scroll-to-edges + (pdf-util-display-edges (pdf-util-scale-edges (pdf-annot-get a 'edges) (pdf-util-image-size t))) diff --git a/lisp/pdf-info.el b/lisp/pdf-info.el index 99a175c..c9d247d 100644 --- a/lisp/pdf-info.el +++ b/lisp/pdf-info.el @@ -1052,7 +1052,10 @@ the caller." (cons (pdf-util-hexcolor fg) (cons (pdf-util-hexcolor bg) - (apply 'append edges))))) + (mapcar + (lambda (e) + (mapconcat 'number-to-string e " ")) + edges))))) selections)))) diff --git a/lisp/pdf-isearch.el b/lisp/pdf-isearch.el index 03ab154..57f4b30 100644 --- a/lisp/pdf-isearch.el +++ b/lisp/pdf-isearch.el @@ -32,91 +32,68 @@ ;;; Code: -;; -;; *Customizable variables -;; + + +;; * ================================================================== * +;; * Customizations +;; * ================================================================== * (defgroup pdf-isearch nil "Isearch in pdf buffers." :group 'pdf-tools) -(defcustom pdf-isearch-convert-commands - '("-fuzz" "30%%" "-region" "%g" - "-fill" "%b" "-draw" "color 0,-1 replace") - "The commands for the external convert program. - -This should be a list of strings, possibly containing special -escape characters. Every found match produces one such command -in the pipeline of the program. The format is used with the -function `format-spec' and the following specs are available: - -%g -- Expands to the geometry of the match, i.e. WxH+X+Y. -%f -- Expands to the foreground color. -%b -- Expands to the background color. -%x -- Expands to the left edge of the match. -%X -- Expands to the right edge of the match. -%y -- Expands to the top edge of the match. -%Y -- Expands to the bottom edge of the match. -%w -- Expands to the width of the match. -%h -- Expands to the height of the match -%W -- Expands to the width of the file image. -%H -- Expands to the height of the file image. -%s -- Expands to the matched text (FIXME: Not implemented). - -Keep in mind, that every element of this list is treated as one -argument for the convert program. Also note, that the notion of -image-size may be different between Emacs and the image on disk. -All format spec coordinates are with respect to the actual -image (the one convert operates on). - -See url `http://www.imagemagick.org/script/convert.php'." - :group 'pdf-isearch - :type '(repeat string) - :link '(url-link "http://www.imagemagick.org/script/convert.php")) - (defface pdf-isearch-match '((((background dark)) (:inherit isearch)) (((background light)) (:inherit isearch))) "Face used to determine the colors of the current match." - ;; :group 'pdf-isearch + :group 'pdf-isearch :group 'pdf-tools-faces) (defface pdf-isearch-lazy '((((background dark)) (:inherit lazy-highlight)) (((background light)) (:inherit lazy-highlight))) "Face used to determine the colors of non-current matches." - ;; :group 'pdf-isearch + :group 'pdf-isearch :group 'pdf-tools-faces) (defface pdf-isearch-batch '((((background dark)) (:inherit match)) (((background light)) (:inherit match))) "Face used to determine the colors in `pdf-isearch-batch-mode'." - ;; :group 'pdf-isearch + :group 'pdf-isearch :group 'pdf-tools-faces) -;; +(defcustom pdf-isearch-cache-images nil + "Whether already displayed images should be cached. + +FIXME: Explain." + :group 'pdf-isearch + :type 'boolean) + + + + +;; * ================================================================== * ;; * Internal Variables -;; +;; * ================================================================== * -(defvar-local pdf-isearch-page nil +(defvar-local pdf-isearch-current-page nil "The page that is currently searched.") (defvar-local pdf-isearch-current-match nil "A list (LEFT TOP RIGHT BOT) of the current match or nil.") -(defvar-local pdf-isearch-matches nil +(defvar-local pdf-isearch-current-matches nil "A list of matches of the last search.") -(defvar-local pdf-isearch-search-parameter nil - "A list of search parameter (search-string, regex-p and case-fold).") +(defvar-local pdf-isearch-current-parameter nil + "A list of search parameter \(search-string regex-p case-fold\).") -(defvar-local pdf-isearch-convert-process nil - "Process used to convert images.") -;; + +;; * ================================================================== * ;; * Modes -;; +;; * ================================================================== * (defvar pdf-isearch-minor-mode-map (let ((kmap (make-sparse-keymap))) @@ -161,19 +138,15 @@ from stopping at and highlighting every single match, but rather display them batch-wise. Here a batch means a number of matches currently visible in the selected window. -Performance is also greatly influenced by the kind of image the -convert program produces. This may be determined by the variable -`pdf-util-fast-image-format'. - -The kind of highlighting is determined by the variable -`pdf-isearch-convert-commands' and the three faces pdf-isearch-match -\(for the current match\), pdf-isearch-lazy \(for all other matches\) -and pdf-isearch-batch \(when in batch mode\), which see. +The kind of highlighting is determined by three faces +`pdf-isearch-match' \(for the current match\), `pdf-isearch-lazy' +\(for all other matches\) and `pdf-isearch-batch' \(when in batch +mode\), which see. Colors may also be influenced by the minor-mode -`pdf-misc-dark-mode'. If this is enabled, each face's dark -colors, are used (see variable `frame-background-mode' etc.), -rather than the light ones. +`pdf-misc-dark-mode'. If this is minor mode enabled, each face's +dark colors, are used (see e.g. `frame-background-mode'), instead +of the light ones. \\{pdf-isearch-minor-mode-map} While in `isearch-mode' the following keys are available. @@ -196,14 +169,16 @@ While in `isearch-mode' the following keys are available. ;; This maybe edit or t, but edit would suppress our cmds ;; in isearch-other-meta-char. (not (not search-exit-option))) + ;; FIXME: Die Variable imagemagick-render-type entweder an anderer + ;; Stelle global setzen oder nur irgendwo auf den + ;; Performancegewinn hinweisen. (when (and (boundp 'imagemagick-render-type) (= 0 imagemagick-render-type)) ;; This enormously speeds up rendering. (setq imagemagick-render-type 1)) (add-hook 'isearch-mode-hook 'pdf-isearch-mode-initialize nil t) (add-hook 'isearch-mode-end-hook 'pdf-isearch-mode-cleanup nil t) - (add-hook 'isearch-update-post-hook 'pdf-isearch-update nil t) - (advice-add 'isearch-done :around 'pdf-isearch-done-advice)) + (add-hook 'isearch-update-post-hook 'pdf-isearch-update nil t)) (t (kill-local-variable 'search-exit-option) (kill-local-variable 'isearch-allow-scroll) @@ -213,41 +188,18 @@ While in `isearch-mode' the following keys are available. (kill-local-variable 'isearch-lazy-highlight) (remove-hook 'isearch-update-post-hook 'pdf-isearch-update t) (remove-hook 'isearch-mode-hook 'pdf-isearch-mode-initialize t) - (remove-hook 'isearch-mode-end-hook 'pdf-isearch-mode-cleanup t) - (advice-remove 'isearch-done 'pdf-isearch-done-advice)))) - -(defvar pdf-isearch-suspended-p nil - "Non-nil in `isearch-mode-end-hook', if isearch is suspended.") + (remove-hook 'isearch-mode-end-hook 'pdf-isearch-mode-cleanup t)))) -(defun pdf-isearch-done-advice (fn &optional nopush edit) - "Make a supsended isearch distinguishable from a quit. -Binds `pdf-isearch-suspended-p' to the EDIT argument around -`isearch-done'." - (let ((pdf-isearch-suspended-p edit)) - (funcall fn nopush edit))) - -(define-minor-mode pdf-isearch-active-mode - "" nil nil nil - (cond - (pdf-isearch-active-mode - ;; The PDF buffer is usually in binary mode, but we probably want - ;; to search for multibyte characters. - ;; (unless enable-multibyte-characters - ;; (set-buffer-multibyte t)) - ) - (t - ;; (unless pdf-isearch-suspended-p - ;; (set-buffer-multibyte nil)) - ))) +(define-minor-mode pdf-isearch-active-mode "" nil nil nil) (define-minor-mode pdf-isearch-batch-mode - "Incrementally search PDF documents in batches. + "Isearch PDF documents batch-wise. If this mode is enabled, isearching does not stop at every match, -but rather moves to next one not currently visible. This +but rather moves to the next one not currently visible. This behaviour is much faster than ordinary isearch, since far less -images have to be created." +different images have to be displayed." nil nil nil :group 'pdf-isearch (when isearch-mode @@ -255,11 +207,17 @@ images have to be created." (pdf-isearch-message (if pdf-isearch-batch-mode "batch mode" "isearch mode")))) -;; -;; * Isearch Interface -;; -(defvar pdf-isearch-filter-matches-function nil) + +;; * ================================================================== * +;; * Isearch interface +;; * ================================================================== * + +(defvar pdf-isearch-filter-matches-function nil + "A function for filtering isearch matches. + +The function receives one argument: a list of edges. It should +return a subset of this list. The edges are in PDF points.") (defun pdf-isearch-search-function (string &rest _) "Search for STRING in the current PDF buffer. @@ -267,32 +225,32 @@ images have to be created." This is a Isearch interface function." (when (> (length string) 0) (let ((same-search-p (pdf-isearch-same-search-p)) - (oldpage pdf-isearch-page) + (oldpage pdf-isearch-current-page) (matches (pdf-isearch-search-page string)) next-match) ;; matches is a list of edges ((x0 y1 x1 y2) ...), sorted top to - ;; bottom ,left to right, + ;; bottom ,left to right, in points (unless isearch-forward (setq matches (reverse matches))) (when pdf-isearch-filter-matches-function (setq matches (funcall pdf-isearch-filter-matches-function matches))) ;; Where to go next ? - (setq pdf-isearch-page (pdf-view-current-page) - pdf-isearch-matches matches + (setq pdf-isearch-current-page (pdf-view-current-page) + pdf-isearch-current-matches matches next-match (pdf-isearch-next-match - oldpage pdf-isearch-page + oldpage pdf-isearch-current-page pdf-isearch-current-match matches same-search-p isearch-forward) - pdf-isearch-search-parameter + pdf-isearch-current-parameter (list string nil isearch-case-fold-search)) (cond (next-match (setq pdf-isearch-current-match next-match) (pdf-isearch-hl-matches next-match matches) (pdf-isearch-focus-match next-match) - ;; Is this necessary ? Does this mess up isearch ? + ;; Don't get off track. (when (or (and (bobp) (not isearch-forward)) (and (eobp) isearch-forward)) (goto-char (1+ (/ (buffer-size) 2)))) @@ -302,36 +260,34 @@ This is a Isearch interface function." (re-search-backward "."))) (t (let ((next-page (pdf-isearch-find-next-matching-page - string pdf-isearch-page isearch-forward t))) - (when nil ;; next-page - (let ((pdf-render-inhibit-display t)) - (pdf-view-goto-page next-page)) + string pdf-isearch-current-page isearch-forward t))) + (when next-page + (pdf-view-goto-page next-page) (pdf-isearch-search-function string)))))))) (defun pdf-isearch-push-state-function () "Push the current search state. This is a Isearch interface function." - (let ((hscroll (* (window-hscroll) (frame-char-width))) + (let ((hscroll (window-hscroll)) (vscroll (window-vscroll nil t)) - (parms pdf-isearch-search-parameter) - (matches pdf-isearch-matches) + (parms pdf-isearch-current-parameter) + (matches pdf-isearch-current-matches) (match pdf-isearch-current-match) - (page pdf-isearch-page)) + (page pdf-isearch-current-page)) (lambda (_state) - (setq pdf-isearch-search-parameter parms - pdf-isearch-matches matches + (setq pdf-isearch-current-parameter parms + pdf-isearch-current-matches matches pdf-isearch-current-match match - pdf-isearch-page page) + pdf-isearch-current-page page) - (let ((pdf-render-inhibit-display t)) - (pdf-view-goto-page pdf-isearch-page)) + (pdf-view-goto-page pdf-isearch-current-page) (when pdf-isearch-current-match (pdf-isearch-hl-matches pdf-isearch-current-match - pdf-isearch-matches)) - (pdf-util-set-window-pixel-hscroll hscroll) - (pdf-util-set-window-pixel-vscroll vscroll)))) + pdf-isearch-current-matches)) + (set-window-hscroll nil hscroll) + (set-window-vscroll nil vscroll t)))) (defun pdf-isearch-wrap-function () "Go to first or last page. @@ -339,10 +295,9 @@ This is a Isearch interface function." This is a Isearch interface function." (let ((page (if isearch-forward 1 - (pdf-info-number-of-pages)))) + (pdf-cache-number-of-pages)))) (unless (= page (pdf-view-current-page)) - (let ((pdf-render-inhibit-display t)) - (pdf-view-goto-page page)) + (pdf-view-goto-page page) (let ((next-screen-context-lines 0)) (if (= page 1) (image-scroll-down) @@ -354,18 +309,17 @@ This is a Isearch interface function." This is a Isearch interface function." (pdf-isearch-active-mode -1) - (pdf-view-redisplay) - (pdf-util-cache-clear "pdf-isearch")) + (pdf-view-redisplay)) (defun pdf-isearch-mode-initialize () "Initialize isearching. This is a Isearch interface function." (pdf-isearch-active-mode 1) - (setq pdf-isearch-page (pdf-view-current-page) + (setq pdf-isearch-current-page (pdf-view-current-page) pdf-isearch-current-match nil - pdf-isearch-matches nil - pdf-isearch-search-parameter nil) + pdf-isearch-current-matches nil + pdf-isearch-current-parameter nil) (goto-char (1+ (/ (buffer-size) 2)))) (defun pdf-isearch-same-search-p (&optional ignore-search-string-p) @@ -374,11 +328,11 @@ This is a Isearch interface function." Parameter inspected are `isearch-string' (unless IGNORE-SEARCH-STRING-P is t) and `isearch-case-fold-search'. If there was no previous search, this function returns t." - (or (null pdf-isearch-search-parameter) + (or (null pdf-isearch-current-parameter) (if ignore-search-string-p - (equal (cdr pdf-isearch-search-parameter) + (equal (cdr pdf-isearch-current-parameter) (list isearch-regexp isearch-case-fold-search)) - (equal pdf-isearch-search-parameter + (equal pdf-isearch-current-parameter (list isearch-string isearch-regexp isearch-case-fold-search))))) @@ -402,14 +356,14 @@ there was no previous search, this function returns t." (defun pdf-isearch-redisplay () "Redisplay the current highlighting." (pdf-isearch-hl-matches pdf-isearch-current-match - pdf-isearch-matches)) + pdf-isearch-current-matches)) (defun pdf-isearch-update () "Update search and redisplay, if necessary." (unless (pdf-isearch-same-search-p t) - (setq pdf-isearch-search-parameter + (setq pdf-isearch-current-parameter (list isearch-string nil isearch-case-fold-search) - pdf-isearch-matches + pdf-isearch-current-matches (pdf-isearch-search-page isearch-string)) (pdf-isearch-redisplay))) @@ -424,20 +378,23 @@ there was no previous search, this function returns t." (sit-for 1)) (message "%s" fmt)))) -;; + + +;; * ================================================================== * ;; * Interface to epdfinfo -;; +;; * ================================================================== * (defun pdf-isearch-search-page (string &optional page) "Search STRING on PAGE in the current window. -Returns a list of edges (LEFT TOP RIGHT BOTTOM) in image +Returns a list of edges (LEFT TOP RIGHT BOTTOM) in PDF coordinates, sorted top to bottom, then left to right." (unless page (setq page (pdf-view-current-page))) (let ((case-fold-search isearch-case-fold-search)) - (mapcar 'car (cdar (pdf-info-search - string nil page))))) + (pdf-util-scale-relative-to-pixel + (mapcar 'car (cdar (pdf-info-search + string nil page)))))) (defun pdf-isearch-find-next-matching-page (string page &optional forward-p interactive-p) @@ -454,7 +411,7 @@ is no such page." (1+ page)) (cons (1- page) (1- page)))) - (final-page (and forward-p (pdf-info-number-of-pages))) + (final-page (and forward-p (pdf-cache-number-of-pages))) matched-page reporter) @@ -467,7 +424,6 @@ is no such page." (setq matched-page (if forward-p (caar matches) (caar (last matches))))) - ;; (logger "%s %s %s" pages matched-page pdf-isearch-search-parameter) (setq incr (* incr 2)) (cond (forward-p (setcar pages (1+ (cdr pages))) @@ -493,9 +449,11 @@ is no such page." (- page (car pages))))))) matched-page)) -;; + + +;; * ================================================================== * ;; * Isearch Behavior -;; +;; * ================================================================== * (defun pdf-isearch-next-match-isearch (last-page this-page last-match matches same-search-p @@ -512,7 +470,7 @@ match." (if forward (cons iedges-left iedges-top) (cons iedges-right iedges-bot))))) - (pdf-isearch-nearest-match pos matches forward))) + (pdf-isearch-closest-match pos matches forward))) ((not (eq last-page this-page)) ;; First match from top-left or bottom-right of the new ;; page. @@ -523,21 +481,13 @@ match." (cadr (member last-match matches)))) (matches ;; Next match of new search closest to the last one. - (pdf-isearch-nearest-match + (pdf-isearch-closest-match last-match matches forward)))) -(defun pdf-isearch-focus-match-isearch (match &optional eager-p) +(defun pdf-isearch-focus-match-isearch (match) "Make the image area in MATCH visible in the selected window." - (unless (image-get-display-property) - (error "No image found in buffer")) - (let ((hscroll (pdf-util-required-hscroll match eager-p)) - (vscroll (pdf-util-required-vscroll match eager-p))) - (when hscroll - (pdf-util-set-window-pixel-hscroll hscroll)) - (when vscroll - (pdf-util-set-window-pixel-vscroll vscroll))) - nil) + (pdf-util-display-edges match)) (defun pdf-isearch-next-match-batch (last-page this-page last-match matches same-search-p @@ -562,11 +512,46 @@ match." (defun pdf-isearch-focus-match-batch (match) "Make the image area in MATCH eagerly visible in the selected window." - (pdf-isearch-focus-match-isearch match t)) + (pdf-util-display-edges match t)) + +(defun pdf-isearch-closest-match (match-or-pos list-of-matches + &optional forward-p) + "Find the nearest element to MATCH-OR-POS in LIST-OF-MATCHES. + +The direction in which to look is determined by FORWARD-P. + +MATCH-OR-POS is either a list of edges or a cons (X . Y). +LIST-OF-MATCHES is assumed to be ordered with respect to +FORWARD-P." + + (let ((match (if (not (consp (cdr match-or-pos))) + (list (car match-or-pos) (cdr match-or-pos) + (car match-or-pos) (cdr match-or-pos)) + match-or-pos)) + found edges) + (pdf-util-with-edges (match) + (while (and (not found) + list-of-matches) + (setq edges (car list-of-matches) + list-of-matches (cdr list-of-matches)) + (pdf-util-with-edges (edges) + (when (or (and forward-p + (or (>= edges-top match-bot) + (and (>= edges-top match-top) + (>= edges-right match-right)))) + (and (null forward-p) + (or (<= edges-bot match-top) + (and (<= edges-top match-top) + (<= edges-left match-left))))) + (setq found edges))))) + found)) + + + +;; * ================================================================== * +;; * Display +;; * ================================================================== * -;; -;; * Highlighting matches -;; (defun pdf-isearch-current-colors () "Return the current color set. @@ -591,9 +576,9 @@ MATCH-BG LAZY-FG LAZY-BG\)." (cdr lazy))))))) (defun pdf-isearch-hl-matches (current matches) - "Highlighting edges CURRENT and MATCHES using the convert program." + "Highlighting edges CURRENT and MATCHES." (let* ((hash (sxhash (cons current matches))) - (width (car (image-size (pdf-view-current-image) t))) + (width (car (pdf-view-image-size))) (page (pdf-view-current-page)) (data ;; (pdf-cache-lookup-image page width nil hash) )) @@ -602,7 +587,6 @@ MATCH-BG LAZY-FG LAZY-BG\)." data (pdf-view-image-type) t)) (let* ((window (selected-window)) (buffer (current-buffer)) - (pdf-info-cancelable nil) (pdf-info-asynchronous (lambda (status file) (when (and (null status) @@ -616,7 +600,6 @@ MATCH-BG LAZY-FG LAZY-BG\)." (eq page (pdf-view-current-page)) (file-readable-p file)) (let ((data (pdf-util-munch-file file))) - (setq pdf-isearch-query-cookie nil) (pdf-cache-put-image page width data hash) (pdf-view-display-image (create-image data (pdf-view-image-type) t))))))))) @@ -624,107 +607,74 @@ MATCH-BG LAZY-FG LAZY-BG\)." (pdf-isearch-current-colors) (pdf-info-renderpage-selection page width nil - `(,fg1 ,bg1 ,current) - `(,fg2 ,bg2 ,@(remq current matches)))))))) + `(,fg1 ,bg1 ,(pdf-util-scale-pixel-to-relative current)) + `(,fg2 ,bg2 ,@(pdf-util-scale-pixel-to-relative + (remq current matches))))))))) -;; -;; * Utility functions and macros -;; -(defun pdf-isearch-nearest-match (match-or-pos list-of-matches - &optional forward-p) - "Find the nearest element to MATCH-OR-POS in LIST-OF-MATCHES. - -The direction in which to look is determined by FORWARD-P. - -MATCH-OR-POS is either a list of edges or a cons (X . Y). -LIST-OF-MATCHES is assumed to be ordered with respect to -FORWARD-P." - - (let ((match (if (not (consp (cdr match-or-pos))) - (list (car match-or-pos) (cdr match-or-pos) - (car match-or-pos) (cdr match-or-pos)) - match-or-pos)) - found edges) - (pdf-util-with-edges (match) - (while (and (not found) - list-of-matches) - (setq edges (car list-of-matches) - list-of-matches (cdr list-of-matches)) - (pdf-util-with-edges (edges) - (when (or (and forward-p - (or (>= edges-top match-bot) - (and (>= edges-top match-top) - (>= edges-right match-right)))) - (and (null forward-p) - (or (<= edges-bot match-top) - (and (<= edges-top match-top) - (<= edges-left match-left))))) - (setq found edges))))) - found)) +;; The following isearch-search function is debugable. +;; +(defun isearch-search () + ;; Do the search with the current search string. + (if isearch-message-function + (funcall isearch-message-function nil t) + (isearch-message nil t)) + (if (and (eq isearch-case-fold-search t) search-upper-case) + (setq isearch-case-fold-search + (isearch-no-upper-case-p isearch-string isearch-regexp))) + (condition-case lossage + (let ((inhibit-point-motion-hooks + ;; FIXME: equality comparisons on functions is asking for trouble. + (and (eq isearch-filter-predicate 'isearch-filter-visible) + search-invisible)) + (inhibit-quit nil) + (case-fold-search isearch-case-fold-search) + (retry t)) + (setq isearch-error nil) + (while retry + (setq isearch-success + (isearch-search-string isearch-string nil t)) + ;; Clear RETRY unless the search predicate says + ;; to skip this search hit. + (if (or (not isearch-success) + (bobp) (eobp) + (= (match-beginning 0) (match-end 0)) + (funcall isearch-filter-predicate + (match-beginning 0) (match-end 0))) + (setq retry nil))) + (setq isearch-just-started nil) + (if isearch-success + (setq isearch-other-end + (if isearch-forward (match-beginning 0) (match-end 0))))) + + (quit (isearch-unread ?\C-g) + (setq isearch-success nil)) + + (invalid-regexp + (setq isearch-error (car (cdr lossage))) + (if (string-match + "\\`Premature \\|\\`Unmatched \\|\\`Invalid " + isearch-error) + (setq isearch-error "incomplete input"))) + + (search-failed + (setq isearch-success nil) + (setq isearch-error (nth 2 lossage))) + + ;; (error + ;; ;; stack overflow in regexp search. + ;; (setq isearch-error (format "%s" lossage))) + ) -;; Redefinition: This isearch-search function is debugable. -;; (defun isearch-search () -;; ;; Do the search with the current search string. -;; (if isearch-message-function -;; (funcall isearch-message-function nil t) -;; (isearch-message nil t)) -;; (if (and (eq isearch-case-fold-search t) search-upper-case) -;; (setq isearch-case-fold-search -;; (isearch-no-upper-case-p isearch-string isearch-regexp))) -;; (condition-case lossage -;; (let ((inhibit-point-motion-hooks -;; ;; FIXME: equality comparisons on functions is asking for trouble. -;; (and (eq isearch-filter-predicate 'isearch-filter-visible) -;; search-invisible)) -;; (inhibit-quit nil) -;; (case-fold-search isearch-case-fold-search) -;; (retry t)) -;; (setq isearch-error nil) -;; (while retry -;; (setq isearch-success -;; (isearch-search-string isearch-string nil t)) -;; ;; Clear RETRY unless the search predicate says -;; ;; to skip this search hit. -;; (if (or (not isearch-success) -;; (bobp) (eobp) -;; (= (match-beginning 0) (match-end 0)) -;; (funcall isearch-filter-predicate -;; (match-beginning 0) (match-end 0))) -;; (setq retry nil))) -;; (setq isearch-just-started nil) -;; (if isearch-success -;; (setq isearch-other-end -;; (if isearch-forward (match-beginning 0) (match-end 0))))) - -;; (quit (isearch-unread ?\C-g) -;; (setq isearch-success nil)) - -;; (invalid-regexp -;; (setq isearch-error (car (cdr lossage))) -;; (if (string-match -;; "\\`Premature \\|\\`Unmatched \\|\\`Invalid " -;; isearch-error) -;; (setq isearch-error "incomplete input"))) - -;; (search-failed -;; (setq isearch-success nil) -;; (setq isearch-error (nth 2 lossage))) - -;; ;; (error -;; ;; ;; stack overflow in regexp search. -;; ;; (setq isearch-error (format "%s" lossage))) -;; ) - -;; (if isearch-success -;; nil -;; ;; Ding if failed this time after succeeding last time. -;; (and (isearch--state-success (car isearch-cmds)) -;; (ding)) -;; (if (functionp (isearch--state-pop-fun (car isearch-cmds))) -;; (funcall (isearch--state-pop-fun (car isearch-cmds)) -;; (car isearch-cmds))) -;; (goto-char (isearch--state-point (car isearch-cmds))))) + (if isearch-success + nil + ;; Ding if failed this time after succeeding last time. + (and (isearch--state-success (car isearch-cmds)) + (ding)) + (if (functionp (isearch--state-pop-fun (car isearch-cmds))) + (funcall (isearch--state-pop-fun (car isearch-cmds)) + (car isearch-cmds))) + (goto-char (isearch--state-point (car isearch-cmds))))) (provide 'pdf-isearch) diff --git a/lisp/pdf-util.el b/lisp/pdf-util.el index 14f1c87..39d1fdb 100644 --- a/lisp/pdf-util.el +++ b/lisp/pdf-util.el @@ -28,233 +28,181 @@ (require 'faces) -(defun pdf-util-munch-file (filename &optional multibyte-p) - "Read contents from FILENAME and delete it. - -Return the file's content as a unibyte string, unless MULTIBYTE-P -is non-nil." - (unwind-protect - (with-temp-buffer - (set-buffer-multibyte multibyte-p) - (insert-file-contents-literally filename) - (buffer-substring-no-properties - (point-min) - (point-max))) - (when (and filename - (file-exists-p filename)) - (delete-file filename)))) - -(defun pdf-util-hexcolor (color) - "Return COLOR in hex-format - -Singal an error, if color is invalid." - (let ((values (color-values (string-trim color)))) - (unless values - (signal 'wrong-type-argument (list 'color-defined-p color))) - (apply 'format "#%02x%02x%02x" - (mapcar (lambda (c) (lsh c -8)) - values)))) - + +;; * ================================================================== * +;; * Transforming coordinates +;; * ================================================================== * -(defun pdf-util-image-size (&optional sliced-p) - (image-size (pdf-view-current-image) t)) +(defun pdf-util-scale (list-of-edges-or-pos scale &optional rounding-fn) + "Scale LIST-OF-EDGES-OR-POS by SCALE. -(defun pdf-util-scale (list-of-edges scale &optional rounding-fn) - "Scale LIST-OF-EDGES by SCALE. +SCALE is a cons (SX . SY), by which edges/positions are scaled. +If ROUNDING-FN is non-nil, it should be a function of one +argument, a real value, returning a rounded +value (e.g. `ceiling'). -SCALE is a cons (SX . SY), by which edges are scaled. If -ROUNDING-FN is non-nil, it should be a function of one argument, -a real value, returning a rounded value (e.g. `ceiling'). +The elements in LIST-OF-EDGES-OR-POS should be either a list +\(LEFT TOP RIGHT BOT\) or a position \(X . Y\). -LIST-OF-EDGES may also be a single element. +LIST-OF-EDGES-OR-POS may also be a single such element. -Return scaled list of edges if LIST-OF-EDGES was indeed a list, +Return scaled list of edges if LIST-OF-EDGES-OR-POS was indeed a list, else return the scaled singleton." - (let ((have-list-p (listp (car list-of-edges)))) + (let ((have-list-p (listp (car list-of-edges-or-pos)))) (unless have-list-p - (setq list-of-edges (list list-of-edges))) + (setq list-of-edges-or-pos (list list-of-edges-or-pos))) (let* ((sx (car scale)) (sy (cdr scale)) - (result (mapcar (lambda (edges) - (let ((e (list (* (nth 0 edges) sx) - (* (nth 1 edges) sy) - (* (nth 2 edges) sx) - (* (nth 3 edges) sy)))) - (if rounding-fn - (mapcar rounding-fn e) - e))) - list-of-edges))) + (result + (mapcar + (lambda (edges) + (cond + ((consp (cdr edges)) + (let ((e (list (* (nth 0 edges) sx) + (* (nth 1 edges) sy) + (* (nth 2 edges) sx) + (* (nth 3 edges) sy)))) + (if rounding-fn + (mapcar rounding-fn e) + e))) + (rounding-fn + (cons (funcall rounding-fn (* (car edges) sx)) + (funcall rounding-fn (* (cdr edges) sy)))) + (t + (cons (* (car edges) sx) + (* (cdr edges) sy))))) + list-of-edges-or-pos))) (if have-list-p result (car result))))) -(defun pdf-util-scale-to-pixel (list-of-point-edges - &optional rounding-fn window) - "Scale LIST-OF-EDGES to match SIZE. - -See also `pdf-util-scale'." - ) - -(defun pdf-util-scale-to-points (list-of-pixel-edges - &optional rounding-fn window) - "Scale LIST-OF-EDGES to match SIZE. - -See also `pdf-util-scale'." - ) - - -;; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -;; -;; O L D C O D E -;; -;; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - - - +(defun pdf-util-scale-to (list-of-edges from to &optional rounding-fn) + "Scale LIST-OF-EDGES in FROM basis to TO. +FROM and TO should both be a cons \(WIDTH . HEIGTH\). See also +`pdf-util-scale'." -(require 'cl-lib) -(require 'doc-view) -(require 'format-spec) -(require 'gnus-range) - -;; Compatibility aliases for recent renaming in bzr doc-view.el . -(when (fboundp 'doc-view--current-cache-dir) - (defalias 'doc-view-current-cache-dir 'doc-view--current-cache-dir) - (defvaralias 'doc-view-current-cache-dir 'doc-view--current-cache-dir) - (defvaralias 'doc-view-current-converter-processes 'doc-view--current-converter-processes) - (defvaralias 'doc-view-buffer-file-name 'doc-view--buffer-file-name)) - -(eval-when-compile - (declare-function doc-view-current-cache-dir "pdf-util.el" nil t) - (defvar doc-view-buffer-file-name) - (defvar doc-view-current-converter-processes) - (defvar doc-view-buffer-file-name)) - -;; -;; Variables -;; + (pdf-util-scale list-of-edges + (cons (/ (float (car to)) + (float (car from))) + (/ (float (cdr to)) + (float (cdr from)))) + rounding-fn)) -(defvar-local pdf-util-png-image-size-alist nil - "Alist of cached png image sizes.") +(defun pdf-util-scale-pixel-to-points (list-of-pixel-edges + &optional window) + "Scale LIST-OF-PIXEL-EDGES to point values. -(defvar pdf-util-after-change-page-hook nil - "A hook ran after turning the page.") - -(defvar pdf-util-after-reconvert-hook nil - "A hook ran after the document was reconverted.") - -;; -;; Doc View Buffers -;; +The result depends on the currently displayed page in WINDOW. +See also `pdf-util-scale'." + (pdf-util-assert-pdf-window window) + (pdf-util-scale-to + list-of-pixel-edges + (pdf-view-image-size window) + (pdf-cache-pagesize))) -(defun pdf-util-docview-buffer-p (&optional buffer) - (and (or (null buffer) - (buffer-live-p buffer)) - (save-current-buffer - (and buffer (set-buffer buffer)) - (derived-mode-p 'doc-view-mode)))) +(defun pdf-util-scale-points-to-pixel (list-of-points-edges + &optional window) + "Scale LIST-OF-POINTS-EDGES to point values. -(defun pdf-util-assert-docview-buffer () - (unless (pdf-util-docview-buffer-p) - (error "Buffer is not in DocView mode"))) +The result depends on the currently displayed page in WINDOW. +See also `pdf-util-scale'." + (pdf-util-assert-pdf-window window) + (pdf-util-scale-to + list-of-points-edges + (pdf-cache-pagesize) + (pdf-view-image-size window) + 'round)) + +(defun pdf-util-scale-relative-to-points (list-of-relative-edges + &optional window) + "Scale LIST-OF-RELATIVE-EDGES to point values. + +The result depends on the currently displayed page in WINDOW. +See also `pdf-util-scale'." + (pdf-util-assert-pdf-window window) + (pdf-util-scale-to + list-of-relative-edges + '(1.0 . 1.0) + (pdf-cache-pagesize))) -(defun pdf-util-pdf-buffer-p (&optional buffer) - (and (or (null buffer) - (buffer-live-p buffer)) - (save-current-buffer - (and buffer (set-buffer buffer)) - (derived-mode-p 'pdf-view-mode)))) +(defun pdf-util-scale-points-to-relative (list-of-points-edges + &optional window) + "Scale LIST-OF-POINTS-EDGES to relative values. -(defun pdf-util-assert-pdf-buffer (&optional buffer) - (unless (pdf-util-pdf-buffer-p buffer) - (error "Buffer is not in DocView PDF mode"))) +See also `pdf-util-scale'." + (pdf-util-assert-pdf-window window) + (pdf-util-scale-to + list-of-points-edges + (pdf-cache-pagesize) + '(1.0 . 1.0))) -(defun pdf-util-docview-window-p (&optional window) - (save-selected-window - (and window (select-window window)) - (pdf-util-docview-buffer-p))) +(defun pdf-util-scale-pixel-to-relative (list-of-pixel-edges + &optional window) + "Scale LIST-OF-PIXEL-EDGES to relative values. -(defun pdf-util-assert-docview-window (&optional window) - (unless (pdf-util-docview-window-p window) - (error "Window's buffer is not in DocView mode"))) +The result depends on the currently displayed page in WINDOW. +See also `pdf-util-scale'." + (pdf-util-assert-pdf-window window) + (pdf-util-scale-to + list-of-pixel-edges + (pdf-view-image-size window) + '(1.0 . 1.0))) -(defun pdf-util-pdf-window-p (&optional window) - (save-selected-window - (and window (select-window window)) - (pdf-util-pdf-buffer-p))) - -(defun pdf-util-assert-pdf-window (&optional window) - (unless (pdf-util-pdf-window-p window) - (error "Window's buffer is not in DocView PDF mode"))) - -(defun pdf-util-doc-view-windows (&optional buffer) - (unless buffer (setq buffer (current-buffer))) - (with-current-buffer buffer - (pdf-util-assert-docview-buffer)) - (let (windows) - (walk-windows - (lambda (win) - (with-selected-window win - (when (eq (current-buffer) buffer) - (push win windows)))) - 'no-mini t) - windows)) - -(defadvice doc-view-goto-page (around pdf-util activate) - "Run `pdf-util-after-change-page-hook'." - (let ((pdf-util-current-page (doc-view-current-page))) - ad-do-it - ;; Delete the annoying tooltip ,,Page x of y''. - (let ((ov (doc-view-current-overlay))) - (when (and ov (stringp (overlay-get ov 'help-echo))) - (overlay-put ov 'help-echo nil))) - (unless (eq pdf-util-current-page - (doc-view-current-page)) - (run-hooks 'pdf-util-after-change-page-hook)))) - -(defadvice doc-view-reconvert-doc (after pdf-links activate) - (run-hooks 'pdf-util-after-reconvert-hook)) -;; +(defun pdf-util-scale-relative-to-pixel (list-of-relative-edges + &optional window) + "Scale LIST-OF-EDGES to match SIZE. -;; -;; +The result depends on the currently displayed page in WINDOW. +See also `pdf-util-scale'." + (pdf-util-assert-pdf-window window) + (pdf-util-scale-to + list-of-relative-edges + '(1.0 . 1.0) + (pdf-view-image-size window) + 'round)) + +(defun pdf-util-translate-edges (list-of-edges-or-pos + offset &optional negative-offset-p) + (let ((have-list-p (listp (car list-of-edges-or-pos)))) + (unless have-list-p + (setq list-of-edges-or-pos (list list-of-edges-or-pos))) + (let* ((ox (if negative-offset-p + (- (car offset)) + (car offset))) + (oy (if negative-offset-p + (- (cdr offset)) + (cdr offset))) + (result + (mapcar + (lambda (edges) + (cond + ((consp (cdr edges)) + (list (+ (nth 0 edges) ox) + (+ (nth 1 edges) oy) + (+ (nth 2 edges) ox) + (+ (nth 3 edges) oy))) + (t + (cons (+ (car edges) ox) + (+ (cdr edges) oy))))) + list-of-edges-or-pos))) + (if have-list-p + result + (car result))))) -(defun pdf-util-assert-derived-mode (&rest modes) - (unless (apply 'derived-mode-p modes) - (error "Buffer is not derived from %s" - (concat (mapconcat 'symbol-name (butlast modes) ", ") - (if (cdr modes) " or ") - (symbol-name (car (last modes))))))) - -(defun pdf-util-page-displayed-p () - (consp (ignore-errors - (doc-view-current-image)))) - -(defun pdf-util-page-displayable-p (&optional page) - (unless page (setq page (doc-view-current-page))) - (file-readable-p - (expand-file-name - (format "page-%d.png" page) - (doc-view-current-cache-dir)))) - + +;; * ================================================================== * +;; * Scrolling +;; * ================================================================== * -(defun pdf-util-current-image-file (&optional page) - (expand-file-name (format "page-%d.png" - (or page (doc-view-current-page))) - (doc-view-current-cache-dir))) -;; -;; Handling Edges -;; (defmacro pdf-util-with-edges (list-of-edges &rest body) (declare (indent 1) (debug (sexp &rest form))) (unless (cl-every 'symbolp list-of-edges) - (signal 'wrong-type-argument (list 'symbolp list-of-edges))) + (signal 'wrong-type-argument (list 'list-of-symbols list-of-edges))) (let ((list-of-syms (mapcar (lambda (edge) (cons edge (mapcar @@ -262,200 +210,31 @@ See also `pdf-util-scale'." (intern (format "%s-%s" edge kind))) '(left top right bot width height)))) list-of-edges))) - (let ((lisp (macroexpand-all - `(cl-symbol-macrolet - ,(apply 'nconc - (mapcar - (lambda (edge-syms) - (let ((edge (nth 0 edge-syms)) - (syms (cdr edge-syms))) - `((,(pop syms) (nth 0 ,edge)) - (,(pop syms) (nth 1 ,edge)) - (,(pop syms) (nth 2 ,edge)) - (,(pop syms) (nth 3 ,edge)) - (,(pop syms) (- (nth 2 ,edge) - (nth 0 ,edge))) - (,(pop syms) (- (nth 3 ,edge) - (nth 1 ,edge)))))) - list-of-syms)) - ,@body)))) - ;; get rid of silly nested (progn (progn ... - (while (eq 'progn (car-safe (nth 1 lisp))) - (setq lisp (nth 1 lisp))) - lisp))) - -(defun pdf-util-scale-edges (list-of-edges scale) - "Scale LIST-OF-EDGES in both directions by SCALE. - -SCALE is a cons (SX . SY), by which edges are scaled and defaults -to the scale of the image in the current window." - - (let ((have-list-p (listp (car list-of-edges)))) - (unless have-list-p - (setq list-of-edges (list list-of-edges))) - (let* ((sx (car scale)) - (sy (cdr scale)) - (round-p (or (> sx 1) (> sy 1))) - (result (mapcar (lambda (edges) - (let ((e (list (* (nth 0 edges) sx) - (* (nth 1 edges) sy) - (* (nth 2 edges) sx) - (* (nth 3 edges) sy)))) - (if round-p - (mapcar 'floor e) - e))) - list-of-edges))) - (if have-list-p - result - (car result))))) - -(defun pdf-util-translate-edges (list-of-edges offset &optional inverse-p) - (let ((have-list-p (listp (car list-of-edges)))) - (if (equal offset '(0 . 0)) - list-of-edges - (unless have-list-p - (setq list-of-edges (list list-of-edges))) - (let* ((ox (if inverse-p - (- (car offset)) - (car offset))) - (oy (if inverse-p - (- (cdr offset)) - (cdr offset))) - (result (mapcar (lambda (edges) - (mapcar 'round - (list (+ (nth 0 edges) ox) - (+ (nth 1 edges) oy) - (+ (nth 2 edges) ox) - (+ (nth 3 edges) oy)))) - list-of-edges))) - (if have-list-p - result - (car result)))))) - -(defun pdf-util-transform-edges (list-of-edges scale offset) - (pdf-util-translate-edges - (pdf-util-scale-edges list-of-edges scale) - offset)) - -(defun pdf-util-enlarge-edges (list-of-edges dx dy) - (let ((have-list-p (listp (car list-of-edges)))) - (unless have-list-p - (setq list-of-edges (list list-of-edges))) - (let ((result (mapcar (lambda (edges) - (list (- (nth 0 edges) dx) - (- (nth 1 edges) dy) - (+ (nth 2 edges) dx) - (+ (nth 3 edges) dy))) - list-of-edges))) - (if have-list-p - result - (car result))))) - -(defun pdf-utils-edges-inside-p (edges pos &optional epsilon) - (pdf-utils-edges-contained-p - edges - (list (car pos) (cdr pos) (car pos) (cdr pos)) - epsilon)) - -(defun pdf-utils-edges-contained-p (edges contained &optional epsilon) - (unless epsilon (setq epsilon 0)) - (pdf-util-with-edges (edges contained) - (and (<= (- edges-left epsilon) - contained-left) - (>= (+ edges-right epsilon) - contained-right) - (<= (- edges-top epsilon) - contained-top) - (>= (+ edges-bot epsilon) - contained-bot)))) - -(defun pdf-utils-edges-disjoint-p (edges1 edges2 &optional epsilon) - (unless epsilon (setq epsilon 0)) - (pdf-util-with-edges (edges1 edges2) - (or (<= (- edges2-right epsilon) - edges1-left) - (<= (- edges2-bot epsilon) - edges1-top) - (>= (+ edges2-left epsilon) - edges1-right) - (>= (+ edges2-top epsilon) - edges1-bot)))) - -(defun pdf-utils-edges-intersection (e1 e2) - (pdf-util-with-edges (edges1 e1 e2) - (let ((left (max e1-left e2-left)) - (top (max e1-top e2-top)) - (right (min e1-right e2-right)) - (bot (min e1-bot e2-bot))) - (when (and (<= left right) - (<= top bot)) - (list left top right bot))))) - -(defun pdf-utils-edges-intersection-area (e1 e2) - (let ((inters (pdf-utils-edges-intersection e1 e2))) - (if (null inters) - 0 - (pdf-util-with-edges (inters) - (* inters-width inters-height))))) - - -;; -;; Handling Images In Windows -;; - -(defcustom pdf-util-fast-image-format nil - "An image format appropriate for fast displaying. - -This should be the string of a file extension of a supported (by -Emacs and convert) image format. If nil, the value is determined -automatically. - -Different formats have different properties, with respect to -Emacs loading time, convert creation time and the file-size. In -general, uncompressed formats are faster, but may need a fair -amount of (temporary) disk space." - :group 'pdf-tools) - -(defun pdf-util-fast-image-format () - "Return an image format appropriate for fast displaying. - -This function returns a file extension as a string, without the -dot." - (or pdf-util-fast-image-format - (setq pdf-util-fast-image-format - (if (fboundp 'imagemagick-types) - (cond - ((memq 'BMP2 (imagemagick-types)) - "bmp2") - ((memq 'JPEG (imagemagick-types)) - "jpeg") - (t - "png")) - "png")))) - -(defun pdf-util-image-offset () - (let* ((slice (pdf-view-current-slice))) - (if slice - (cons (nth 0 slice) (nth 1 slice)) - (cons 0 0)))) - -(defun pdf-util-set-window-pixel-vscroll (vscroll) - (setq vscroll (max (round vscroll) 0)) - (set-window-vscroll (selected-window) vscroll t) - (setf (image-mode-window-get 'vscroll) (window-vscroll)) - nil) - -(defun pdf-util-set-window-pixel-hscroll (hscroll) - (setq hscroll (max 0 (round (/ hscroll (float (frame-char-width)))))) - (setf (image-mode-window-get 'hscroll) hscroll) - (set-window-hscroll nil hscroll) - nil) - -(defun pdf-util-image-edges-in-window (&optional window) - "Return the visible edges of some image in WINDOW." + (macroexpand-all + `(cl-symbol-macrolet + ,(apply 'nconc + (mapcar + (lambda (edge-syms) + (let ((edge (nth 0 edge-syms)) + (syms (cdr edge-syms))) + `((,(pop syms) (nth 0 ,edge)) + (,(pop syms) (nth 1 ,edge)) + (,(pop syms) (nth 2 ,edge)) + (,(pop syms) (nth 3 ,edge)) + (,(pop syms) (- (nth 2 ,edge) + (nth 0 ,edge))) + (,(pop syms) (- (nth 3 ,edge) + (nth 1 ,edge)))))) + list-of-syms)) + ,@body)))) + +(defun pdf-util-image-displayed-edges (&optional window) + "Return the visible region of the image in WINDOW. + +Returns a list of pixel edges." (let* ((edges (window-inside-pixel-edges window)) - (isize (pdf-util-image-size)) - (offset (pdf-util-image-offset)) + (isize (pdf-view-image-size window)) + (offset (pdf-view-image-offset window)) (hscroll (* (window-hscroll window) (frame-char-width (window-frame window)))) (vscroll (window-vscroll window t)) @@ -467,17 +246,16 @@ dot." (+ y0 (- (nth 3 edges) (nth 1 edges)))))) (list x0 y0 x1 y1))) - (defun pdf-util-required-hscroll (edges &optional eager-p context-pixel) - (unless context-pixel (setq context-pixel 0;; (frame-char-width) - )) + (unless context-pixel + (setq context-pixel 0)) (let* ((win (window-inside-pixel-edges)) - (image-width (car (pdf-util-image-size t))) + (image-width (car (pdf-view-image-size t))) (image-left (* (frame-char-width) (window-hscroll))) (edges (pdf-util-translate-edges edges - (pdf-util-image-offset) t))) + (pdf-view-image-offset) t))) (pdf-util-with-edges (win edges) (let* ((edges-left (- edges-left context-pixel)) (edges-right (+ edges-right context-pixel))) @@ -495,11 +273,11 @@ dot." (defun pdf-util-required-vscroll (edges &optional eager-p context-pixel) (let* ((win (window-inside-pixel-edges)) - (image-height (cdr (pdf-util-image-size t))) + (image-height (cdr (pdf-view-image-size t))) (image-top (window-vscroll nil t)) (edges (pdf-util-translate-edges edges - (pdf-util-image-offset) t))) + (pdf-view-image-offset) t))) (pdf-util-with-edges (win edges) (let* ((context-pixel (or context-pixel (* next-screen-context-lines @@ -519,109 +297,221 @@ dot." edges-top (- edges-bot win-height))))))))) -(defun pdf-util-scroll-to-edges (edges &optional eager-p) - (pdf-util-assert-pdf-window) +(defun pdf-util-set-window-pixel-vscroll (vscroll) + (setq vscroll (max (round vscroll) 0)) + (set-window-vscroll (selected-window) vscroll t) + (setf (image-mode-window-get 'vscroll) (window-vscroll)) + nil) + +(defun pdf-util-set-window-pixel-hscroll (hscroll) + (setq hscroll (max 0 (round (/ hscroll (float (frame-char-width)))))) + (setf (image-mode-window-get 'hscroll) hscroll) + (set-window-hscroll nil hscroll) + nil) + +(defun pdf-util-display-edges (edges &optional eager-p) (let ((vscroll (pdf-util-required-vscroll edges eager-p)) (hscroll (pdf-util-required-hscroll edges eager-p))) (when vscroll (pdf-util-set-window-pixel-vscroll vscroll)) (when hscroll (pdf-util-set-window-pixel-hscroll hscroll)))) - -(defmacro pdf-util-save-window-scroll (&rest body) - (declare (indent 0) (debug t)) - (let ((hscroll (make-symbol "hscroll")) - (vscroll (make-symbol "vscroll"))) - `(let ((,hscroll (window-hscroll)) - (,vscroll (window-vscroll))) - (unwind-protect - (progn ,@body) - (image-set-window-hscroll ,hscroll) - (image-set-window-vscroll ,vscroll))))) -(defun pdf-util-read-image-position (prompt) - (pdf-util-assert-pdf-window) - (save-selected-window - (let ((ev (read-event - (propertize prompt 'face 'minibuffer-prompt))) - (buffer (current-buffer))) - (unless (mouse-event-p ev) - (error "Not a mouse event")) - (let ((posn (event-start ev))) - (unless (and (eq (window-buffer - (posn-window posn)) - buffer) - (eq 'image (car-safe (posn-object posn)))) - (error "Invalid image position")) - (posn-object-x-y posn))))) -(defun pdf-util-image-map-mouse-event-proxy (event) - "Remove the POS-OR-AREA symbol from EVENT and restuff it." - (interactive "e") - (setcar (cdr (cadr event)) 1) - (setq unread-command-events (list event))) -(defun pdf-util-image-map-divert-mouse-clicks (id &optional buttons) - (dolist (kind '("" "down-" "drag-")) - (dolist (b (or buttons '(2 3 4 5 6))) - (local-set-key - (vector id (intern (format "%smouse-%d" kind b))) - 'pdf-util-image-map-mouse-event-proxy)))) - + +;; * ================================================================== * +;; * Various +;; * ================================================================== * + +(defun pdf-util-pdf-buffer-p (&optional buffer) + (and (or (null buffer) + (buffer-live-p buffer)) + (save-current-buffer + (and buffer (set-buffer buffer)) + (derived-mode-p 'pdf-view-mode)))) + +(defun pdf-util-assert-pdf-buffer (&optional buffer) + (unless (pdf-util-pdf-buffer-p buffer) + (error "Buffer is not in PDFView mode"))) + +(defun pdf-util-pdf-window-p (&optional window) + (unless window (setq window (selected-window))) + (and (window-live-p window) + (with-selected-window window + (pdf-util-pdf-buffer-p)))) +(defun pdf-util-assert-pdf-window (&optional window) + (unless (pdf-util-pdf-window-p window) + (error "Window's buffer is not in PdfView mode"))) + +(defun pdf-util-munch-file (filename &optional multibyte-p) + "Read contents from FILENAME and delete it. + +Return the file's content as a unibyte string, unless MULTIBYTE-P +is non-nil." + (unwind-protect + (with-temp-buffer + (set-buffer-multibyte multibyte-p) + (insert-file-contents-literally filename) + (buffer-substring-no-properties + (point-min) + (point-max))) + (when (and filename + (file-exists-p filename)) + (delete-file filename)))) + +(defun pdf-util-hexcolor (color) + "Return COLOR in hex-format. + +Singal an error, if color is invalid." + (let ((values (color-values (string-trim color)))) + (unless values + (signal 'wrong-type-argument (list 'color-defined-p color))) + (apply 'format "#%02x%02x%02x" + (mapcar (lambda (c) (lsh c -8)) + values)))) + +(defun pdf-util-tooltip-in-window (text x y &optional window) + (let* ((we (window-inside-absolute-pixel-edges window)) + (dx (round (+ x (nth 0 we)))) + (dy (round (+ y (nth 1 we)))) + (tooltip-frame-parameters + `((left . ,dx) + (top . ,dy) + ,@tooltip-frame-parameters))) + (tooltip-show text))) + +(defun pdf-util-tooltip-arrow (image-top &optional timeout) + (pdf-util-assert-pdf-window) + (when (floatp image-top) + (setq image-top + (round (* image-top (cdr (pdf-view-image-size)))))) + (let* (x-gtk-use-system-tooltips ;allow for display property in tooltip + (dx (+ (or (car (window-margins)) 0) + (car (window-fringes)))) + (dy image-top) + (pos (list dx dy dx (+ dy (* 2 (frame-char-height))))) + (vscroll + (pdf-util-required-vscroll pos)) + (tooltip-frame-parameters + `((border-width . 0) + (internal-border-width . 0) + ,@tooltip-frame-parameters)) + (tooltip-hide-delay (or timeout 3))) + (when vscroll + (pdf-util-set-window-pixel-vscroll vscroll)) + (setq dy (max 0 (- dy + (cdr (pdf-view-image-offset)) + (window-vscroll nil t)))) + (when (overlay-get (doc-view-current-overlay) 'before-string) + (let* ((e (window-inside-pixel-edges)) + (xw (pdf-util-with-edges (e) e-width))) + (cl-incf dx (/ (- xw (car (pdf-view-image-size))) 2)))) + (pdf-util-tooltip-in-window + (propertize + " " 'display (propertize + "\u2192" ;;right arrow + 'display '(height 2) + 'face '(:foreground + "orange red" + :background "white"))) + dx dy))) + +(defvar pdf-util--face-colors-cache (make-hash-table)) -;; -;; Converting Images -;; +(defun pdf-util-face-colors (face &optional dark-p) + "Return both colors of FACE as a cons. + +Look also in inherited faces. If DARK-P is non-nil, return dark +colors, otherwise light." + (let* ((bg (if dark-p 'dark 'light)) + (spec (list (get face 'face-defface-spec) + (get face 'theme-face) + (get face 'customized-face))) + (cached (gethash face pdf-util--face-colors-cache))) + (cl-destructuring-bind (&optional cspec color-alist) + cached + (or (and color-alist + (equal cspec spec) + (cdr (assq bg color-alist))) + (let* ((this-bg (frame-parameter nil 'background-mode)) + (frame-background-mode bg) + (f (and (not (eq bg this-bg)) + (x-create-frame-with-faces '((visibility . nil)))))) + (with-selected-frame (or f (selected-frame)) + (unwind-protect + (let ((colors + (cons (face-attribute face :foreground nil 'default) + (face-attribute face :background nil 'default)))) + (puthash face `(,(mapcar 'copy-sequence spec) + ((,bg . ,colors) ,@color-alist)) + pdf-util--face-colors-cache) + colors) + (when (and f (frame-live-p f)) + (delete-frame f))))))))) + +(defun pdf-util-window-attach (awindow &optional window) + "Attach AWINDOW to WINDOW. + +This has the following effect. Whenever WINDOW, defaulting to +the selected window, stops displaying the buffer it currently +displays (e.g., by switching buffers or because it was deleted) +AWINDOW is deleted also." + (unless window (setq window (selected-window))) + (let ((buffer (window-buffer window)) + (hook (make-symbol "window-attach-hook"))) + (fset hook + (lambda () + (when (or (not (window-live-p window)) + (not (eq buffer (window-buffer window)))) + (remove-hook 'window-configuration-change-hook + hook) + ;; Deleting windows inside wcch may cause errors in + ;; windows.el . + (run-with-timer + 0 nil (lambda (win) + (when (and (window-live-p win) + (not (eq win (selected-window)))) + (delete-window win))) + awindow)))) + (add-hook 'window-configuration-change-hook hook))) + +(defun display-buffer-split-below-and-attach (buf alist) + "Display buffer action using `pdf-util-window-attach'." + (let ((window (selected-window)) + (height (cdr (assq 'window-height alist))) + newwin) + (when height + (when (floatp height) + (setq height (round (* height (frame-height))))) + (setq height (- (max height window-min-height)))) + (setq newwin (window--display-buffer + buf + (split-window-below height) + 'window alist display-buffer-mark-dedicated)) + (pdf-util-window-attach newwin window) + newwin)) + + +;; * ================================================================== * +;; * Imagemagick's convert +;; * ================================================================== * + +(defcustom pdf-util-convert-program (executable-find "convert") + "Absolute path to the convert program." + :group 'pdf-tools + :type 'executable) (defun pdf-util-assert-convert-program () (unless (and pdf-util-convert-program (file-executable-p pdf-util-convert-program)) (error "The pdf-util-convert-program is unset or non-executable"))) -(defvar-local pdf-util-png-image-size-resolution nil - "Saved resolution of the current conversion. - -Used to determine whether cached image-file sizes are still -valid.") - -(defun pdf-util-png-image-size (&optional page) - "Return the image size of the image file of the current PAGE. - -This returns a cons \(WIDTH . HEIGHT\) or nil, if not -available (e.g. because it does not exist or is currently written -to)." - - (unless page (setq page (ignore-errors - (doc-view-current-page)))) - (when page - (unless (eq doc-view-resolution - pdf-util-png-image-size-resolution) - (setq pdf-util-png-image-size-resolution doc-view-resolution - pdf-util-png-image-size-alist nil)) - (let ((entry - (cl-assoc page pdf-util-png-image-size-alist - :test 'gnus-member-of-range))) - (if entry - (nth 2 entry) - (let ((page-size (pdf-info-pagesize page))) - (setq entry (car (cl-member page-size - pdf-util-png-image-size-alist - :key 'cadr :test 'equal))) - (unless entry - (let ((size (pdf-util-image-file-size - (pdf-util-current-image-file page)))) - (when size - (setq entry - (list nil page-size size)) - (push entry pdf-util-png-image-size-alist)))) - (when entry - (setcar entry (gnus-range-add - (car entry) (list page))) - (nth 2 entry))))))) - - (defun pdf-util-image-file-size (image-file) + "Determine the size of the image in IMAGE-FILE. + +Returns a cons \(WIDTH . HEIGHT\)." (pdf-util-assert-convert-program) (with-temp-buffer (when (save-excursion @@ -709,7 +599,6 @@ See url `http://www.imagemagick.org/script/convert.php'." out-file)) (defun pdf-util-convert-asynch (in-file out-file &rest spec-and-callback) - ;; Influence compression level with -quality 0-100. (pdf-util-assert-convert-program) (let ((callback (car (last spec-and-callback))) spec) @@ -773,272 +662,106 @@ See url `http://www.imagemagick.org/script/convert.php'." (dolist (fmt cmds) (push (format-spec fmt alist) result)))))))) (nreverse result))) - -;; -;; Caching Converted Images + + + +;; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ;; +;; O L D C O D E +;; +;; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + -(defvar pdf-util-cache-directories nil) - -(defun pdf-util-cache-make-filename (dir &optional extension &rest keys) - (when (symbolp dir) - (setq dir (symbol-name dir))) - (let ((root (pdf-util-cache--get-root-dir))) - (unless root - (error "The DocView cache directory is n/a")) - (let ((file (format "%s.%s" (sha1 (format "%S" keys)) - (or extension "png"))) - (dir (file-name-as-directory - (expand-file-name - dir - root)))) - (unless (file-exists-p dir) - (make-directory dir) - (push dir pdf-util-cache-directories)) - (setq file (expand-file-name file dir)) - (when (file-exists-p file) - (set-file-times file)) - file))) - -(defun pdf-util-cache-files (dir) - (when (symbolp dir) - (setq dir (symbol-name dir))) - (let ((root (pdf-util-cache--get-root-dir))) - (when root - (let ((dir (file-name-as-directory - (expand-file-name - dir - root)))) - (when (file-exists-p dir) - (directory-files - dir t directory-files-no-dot-files-regexp)))))) - -(defun pdf-util-cache-clear (dir) - (when (symbolp dir) - (setq dir (symbol-name dir))) - (let ((root (pdf-util-cache--get-root-dir))) - (when root - (let ((dir (file-name-as-directory - (expand-file-name - dir - root)))) - (when (file-exists-p dir) - (mapc 'clear-image-cache - (directory-files - dir t directory-files-no-dot-files-regexp t)) - (delete-directory dir t)))))) - -(defun pdf-util-cache-clear-all () - (interactive) - (let ((dir (pdf-util-cache--get-root-dir))) - (when (and dir - (file-exists-p dir)) - (with-temp-buffer - ;; Switch to multibyte buffer, because delete-directory has a - ;; filename encoding bug when deleting recursively from - ;; unibyte buffer. - (delete-directory dir t))))) - -(defun pdf-util-cache--get-root-dir () - (when (and (pdf-util-docview-buffer-p) - (doc-view-current-cache-dir) - (file-exists-p (doc-view-current-cache-dir))) - (let ((dir (file-name-as-directory - (expand-file-name - ".pdf-util-cache" - (doc-view-current-cache-dir))))) - (unless (file-exists-p dir) - (make-directory dir)) - (add-hook 'kill-buffer-hook 'pdf-util-cache-clear-all nil t) - dir))) - -(defun pdf-util-cache-clean-globally () - "Remove all not recently used cached images." - (let ((dvcd (expand-file-name doc-view-cache-directory))) - (setq pdf-util-cache-directories - (cl-remove-if-not - (lambda (d) - (and (file-readable-p d) - (string-prefix-p dvcd d))) - pdf-util-cache-directories))) - (let ((now (current-time))) - (dolist (dir pdf-util-cache-directories) - (when (file-readable-p dir) - (dolist (file (directory-files - dir t directory-files-no-dot-files-regexp t)) - (let ((mtime (nth 5 (file-attributes file)))) - (when (and (time-less-p - (time-add mtime (seconds-to-time (* 5 60))) - now) - (not (pdf-util-image-in-use-p file))) - (if (file-directory-p file) - (let ((pdf-util-cache-directories - (list file))) - (pdf-util-cache-clean-globally)) - (clear-image-cache file) - (delete-file file))))) - (when (and (file-readable-p dir) - (null (directory-files - dir t directory-files-no-dot-files-regexp t))) - (delete-directory dir)))))) - -;;(run-with-timer 0 (* 5 60) 'pdf-util-cache-clean-globally) - -(defun pdf-util-image-in-use-p (file) - "Return t if image FILE is displayed in some window." - (cl-labels - ((check-buffer (buffer &optional window) - ;; Deleting a used image-file with imagemagick may crash Emacs, - ;; be thorough. - (with-current-buffer buffer - (save-excursion - (goto-char (point-min)) - (catch 'found - (while (not (eobp)) - (let ((display (get-char-property - (point) 'display window)) - image-file) - (when (and (consp display) - (eq 'image (car display)) - (setq image-file (plist-get (cdr display) :file)) - image-file - (file-equal-p image-file file)) - (throw 'found t))) - (goto-char (next-single-char-property-change - (point) 'display nil (point-max))))))))) - (or (get-window-with-predicate - (lambda (win) - (check-buffer (window-buffer win) win)) - 'no-mini t) - (let ((tip (get-buffer " *tip*"))) - (and (buffer-live-p tip) - (check-buffer tip)))))) + + + + +(require 'cl-lib) +(require 'format-spec) ;; -;; Various Functions +;; Handling Edges ;; -(defun pdf-util-tooltip-in-window (text x y &optional window) - (let* ((we (window-inside-absolute-pixel-edges window)) - (dx (round (+ x (nth 0 we)))) - (dy (round (+ y (nth 1 we)))) - (tooltip-frame-parameters - `((left . ,dx) - (top . ,dy) - ,@tooltip-frame-parameters))) - (tooltip-show text))) -(defun pdf-util-tooltip-arrow (image-top &optional timeout) + + + + +(defun pdf-utils-edges-inside-p (edges pos &optional epsilon) + (pdf-utils-edges-contained-p + edges + (list (car pos) (cdr pos) (car pos) (cdr pos)) + epsilon)) + +(defun pdf-utils-edges-contained-p (edges contained &optional epsilon) + (unless epsilon (setq epsilon 0)) + (pdf-util-with-edges (edges contained) + (and (<= (- edges-left epsilon) + contained-left) + (>= (+ edges-right epsilon) + contained-right) + (<= (- edges-top epsilon) + contained-top) + (>= (+ edges-bot epsilon) + contained-bot)))) + +(defun pdf-utils-edges-intersection (e1 e2) + (pdf-util-with-edges (edges1 e1 e2) + (let ((left (max e1-left e2-left)) + (top (max e1-top e2-top)) + (right (min e1-right e2-right)) + (bot (min e1-bot e2-bot))) + (when (and (<= left right) + (<= top bot)) + (list left top right bot))))) + +(defun pdf-utils-edges-intersection-area (e1 e2) + (let ((inters (pdf-utils-edges-intersection e1 e2))) + (if (null inters) + 0 + (pdf-util-with-edges (inters) + (* inters-width inters-height))))) + + + +(defun pdf-util-read-image-position (prompt) (pdf-util-assert-pdf-window) - (unless (pdf-util-page-displayed-p) - (error "No page displayed in this window")) - (when (floatp image-top) - (setq image-top - (round (* image-top (cdr (pdf-util-image-size)))))) - (let* (x-gtk-use-system-tooltips ;allow for display property in tooltip - (dx (+ (or (car (window-margins)) 0) - (car (window-fringes)))) - (dy image-top) - (pos (list dx dy dx (+ dy (* 2 (frame-char-height))))) - (vscroll - (pdf-util-required-vscroll pos)) - (tooltip-frame-parameters - `((border-width . 0) - (internal-border-width . 0) - ,@tooltip-frame-parameters)) - (tooltip-hide-delay (or timeout 3))) - (when vscroll - (pdf-util-set-window-pixel-vscroll vscroll)) - (setq dy (max 0 (- dy - (cdr (pdf-util-image-offset)) - (window-vscroll nil t)))) - (when (overlay-get (doc-view-current-overlay) 'before-string) - (let* ((e (window-inside-pixel-edges)) - (xw (pdf-util-with-edges (e) e-width))) - (cl-incf dx (/ (- xw (car (pdf-util-image-size))) 2)))) - (pdf-util-tooltip-in-window - (propertize - " " 'display (propertize - "\u2192" ;;right arrow - 'display '(height 2) - 'face '(:foreground - "orange red" - :background "white"))) - dx dy))) + (save-selected-window + (let ((ev (read-event + (propertize prompt 'face 'minibuffer-prompt))) + (buffer (current-buffer))) + (unless (mouse-event-p ev) + (error "Not a mouse event")) + (let ((posn (event-start ev))) + (unless (and (eq (window-buffer + (posn-window posn)) + buffer) + (eq 'image (car-safe (posn-object posn)))) + (error "Invalid image position")) + (posn-object-x-y posn))))) -(defvar pdf-util-face-colors--cache (make-hash-table)) - -(defun pdf-util-face-colors (face &optional dark-p) - "Return both colors of FACE as a cons. +(defun pdf-util-image-map-mouse-event-proxy (event) + "Remove the POS-OR-AREA symbol from EVENT and restuff it." + (interactive "e") + (setcar (cdr (cadr event)) 1) + (setq unread-command-events (list event))) -Look also in inherited faces. If DARK-P is non-nil, return dark -colors, otherwise light." - (let* ((bg (if dark-p 'dark 'light)) - (spec (list (get face 'face-defface-spec) - (get face 'theme-face) - (get face 'customized-face))) - (cached (gethash face pdf-util-face-colors--cache))) - (cl-destructuring-bind (&optional cspec color-alist) - cached - (or (and color-alist - (equal cspec spec) - (cdr (assq bg color-alist))) - (let* ((this-bg (frame-parameter nil 'background-mode)) - (frame-background-mode bg) - (f (and (not (eq bg this-bg)) - (x-create-frame-with-faces '((visibility . nil)))))) - (with-selected-frame (or f (selected-frame)) - (unwind-protect - (let ((colors - (cons (face-attribute face :foreground nil 'default) - (face-attribute face :background nil 'default)))) - (puthash face `(,(mapcar 'copy-sequence spec) - ((,bg . ,colors) ,@color-alist)) - pdf-util-face-colors--cache) - colors) - (when (and f (frame-live-p f)) - (delete-frame f))))))))) +(defun pdf-util-image-map-divert-mouse-clicks (id &optional buttons) + (dolist (kind '("" "down-" "drag-")) + (dolist (b (or buttons '(2 3 4 5 6))) + (local-set-key + (vector id (intern (format "%smouse-%d" kind b))) + 'pdf-util-image-map-mouse-event-proxy)))) + + -(defun pdf-util-window-attach (awindow &optional window) - "Attach AWINDOW to WINDOW. -This has the following effect. Whenever WINDOW, defaulting to -the selected window, stops displaying the buffer it currently -displays (e.g., by switching buffers or because it was deleted) -AWINDOW is deleted." - (unless window (setq window (selected-window))) - (let ((buffer (window-buffer window)) - (hook (make-symbol "window-attach-hook"))) - (fset hook - (lambda () - (when (or (not (window-live-p window)) - (not (eq buffer (window-buffer window)))) - (remove-hook 'window-configuration-change-hook - hook) - ;; Deleting windows inside wcch leads to errors in - ;; windows.el . - (run-with-timer - 0 nil (lambda (win) - (when (and (window-live-p win) - (not (eq win (selected-window)))) - (delete-window win))) - awindow)))) - (add-hook 'window-configuration-change-hook hook))) + +;; +;; Various Functions +;; -(defun display-buffer-split-below-and-attach (buf alist) - (let ((window (selected-window)) - (height (cdr (assq 'window-height alist))) - newwin) - (when height - (when (floatp height) - (setq height (round (* height (frame-height))))) - (setq height (- (max height window-min-height)))) - (setq newwin (window--display-buffer - buf - (split-window-below height) - 'window alist display-buffer-mark-dedicated)) - (pdf-util-window-attach newwin window) - newwin)) (provide 'pdf-util) diff --git a/lisp/pdf-view.el b/lisp/pdf-view.el index 84097ed..fa55216 100644 --- a/lisp/pdf-view.el +++ b/lisp/pdf-view.el @@ -446,18 +446,18 @@ at the top edge of the page moves to the previous page." ;; * Slicing ;; * ================================================================== * -(defun pdf-view-set-slice (x y width height) +(defun pdf-view-set-slice (x y width height &optional window) "Set the slice of the pages that should be displayed. X, Y, WIDTH and HEIGHT should be relative coordinates, i.e. in \[0;1\]. To reset the slice use `pdf-view-reset-slice'." - (unless (equal (pdf-view-current-slice) + (unless (equal (pdf-view-current-slice window) (list x y width height)) - (setf (pdf-view-current-slice) + (setf (pdf-view-current-slice window) (mapcar (lambda (v) (max 0 (min 1 v))) (list x y width height))) - (pdf-view-redisplay))) + (pdf-view-redisplay window))) (defun pdf-view-set-slice-using-mouse () "Set the slice of the images that should be displayed. @@ -483,8 +483,8 @@ dragging it to its bottom-right corner. See also (cons (/ 1.0 (float (car size))) (/ 1.0 (float (cdr size)))))))) -(defun pdf-view-set-slice-from-bounding-box () - "Set the slice from the document's bounding-box. +(defun pdf-view-set-slice-from-bounding-box (&optional window) + "Set the slice from the page's bounding-box. The result is that the margins are almost completely cropped, much more accurate than could be done manually using @@ -492,7 +492,7 @@ much more accurate than could be done manually using See also `pdf-view-bounding-box-margin'." (interactive) - (let* ((bb (pdf-cache-boundingbox (pdf-view-current-page))) + (let* ((bb (pdf-cache-boundingbox (pdf-view-current-page window))) (margin (max 0 (or pdf-view-bounding-box-margin 0))) (slice (list (- (nth 0 bb) (/ margin 2.0)) @@ -502,17 +502,19 @@ See also `pdf-view-bounding-box-margin'." margin) (+ (- (nth 3 bb) (nth 1 bb)) margin)))) - (apply 'pdf-view-set-slice slice))) + (apply 'pdf-view-set-slice + (append slice (and window (list window)))))) -(defun pdf-view-reset-slice () +(defun pdf-view-reset-slice (&optional window) "Reset the current slice. After calling this function the whole page will be visible again." (interactive) - (when (pdf-view-current-slice) - (setf (pdf-view-current-slice) nil) - (pdf-view-redisplay))) + (when (pdf-view-current-slice window) + (setf (pdf-view-current-slice window) nil) + (pdf-view-redisplay window)) + nil) @@ -551,8 +553,32 @@ or png." :width (car size) :map hotspots))) -(defun pdf-view-image-size (&optional window) - (image-size (pdf-view-current-image window) t)) +(defun pdf-view-image-size (&optional displayed-p window) + "Return the size in pixel of the current image. + +If DISPLAYED-P is non-nil, returned the size of the displayed +image. These may be different, if slicing is in use." + (if displayed-p + (with-selected-window (or window (selected-window)) + (image-display-size + (image-get-display-property) t)) + (image-size (pdf-view-current-image window) t))) + +(defalias 'pdf-util-image-size 'pdf-view-image-size) + +(defun pdf-view-image-offset (&optional window) + "Return the offset of the current image. + +It is equal to \(LEFT . TOP\) of the current slice in pixel." + + (let* ((slice (pdf-view-current-slice window))) + (cond + (slice + (pdf-util-scale-relative-to-pixel + (cons (nth 0 slice) (nth 1 slice)) + window)) + (t + (cons 0 0))))) (defun pdf-view-display-page (page &optional window inhibit-hotspots-p) "Display page PAGE in WINDOW." @@ -748,8 +774,6 @@ supercede hotspots in lower ones." (pdf-view-current-page)))))))))) (defun pdf-view--prefetch-pages (window image-width) - (unless pdf-view--prefetch-pages - (pdf-util-debug "Prefetching done.")) (when (and pdf-view--prefetch-pages (eq window (selected-window))) (let ((page (pop pdf-view--prefetch-pages))) @@ -761,18 +785,21 @@ supercede hotspots in lower ones." image-width (* 2 image-width)))) (setq page (pop pdf-view--prefetch-pages))) - (when page + (if (null page) + (pdf-tools-debug "Prefetching done.") (let ((pdf-info-asynchronous (lambda (status data) (when (and (null status) (eq window (selected-window))) - (pdf-cache-put-image page image-width data) - (image-size (pdf-view-create-image page)) - (pdf-util-debug "Prefetched Page %s." page) - ;; Avoid max-lisp-eval-depth - (run-with-timer - 0 nil 'pdf-view--prefetch-pages window image-width))))) + (with-current-buffer (window-buffer) + (pdf-cache-put-image + page image-width (pdf-util-munch-file data)) + (image-size (pdf-view-create-image page)) + (pdf-tools-debug "Prefetched Page %s." page) + ;; Avoid max-lisp-eval-depth + (run-with-timer + 0 nil 'pdf-view--prefetch-pages window image-width)))))) (pdf-info-renderpage page image-width)))))) (defun pdf-view--prefetch-start (buffer) @@ -784,7 +811,7 @@ supercede hotspots in lower ones." (let ((pages (funcall pdf-view-prefetch-pages-function))) (setq pdf-view--prefetch-pages (butlast pages (max 0 (- (length pages) - pdf-cache-image-cache-limit)))) + pdf-cache-image-limit)))) (pdf-view--prefetch-pages (selected-window) (car (pdf-view-desired-image-size)))))) |
