diff options
Diffstat (limited to 'elpa/pdf-tools-20200512.1524/pdf-cache.el')
-rw-r--r-- | elpa/pdf-tools-20200512.1524/pdf-cache.el | 456 |
1 files changed, 0 insertions, 456 deletions
diff --git a/elpa/pdf-tools-20200512.1524/pdf-cache.el b/elpa/pdf-tools-20200512.1524/pdf-cache.el deleted file mode 100644 index 9ed7241..0000000 --- a/elpa/pdf-tools-20200512.1524/pdf-cache.el +++ /dev/null @@ -1,456 +0,0 @@ -;;; pdf-cache.el --- Cache time-critical or frequent epdfinfo queries. -*- lexical-binding:t -*- - -;; Copyright (C) 2013 Andreas Politz - -;; Author: Andreas Politz <politza@fh-trier.de> -;; Keywords: files, doc-view, pdf - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <http://www.gnu.org/licenses/>. - -;;; Commentary: -;; -;;; Code: -;; - -(require 'pdf-info) -(require 'pdf-util) - - -;; * ================================================================== * -;; * Customiazations -;; * ================================================================== * - -(defcustom pdf-cache-image-limit 64 - "Maximum number of cached PNG images per buffer." - :type 'integer - :group 'pdf-cache - :group 'pdf-view) - -(defcustom pdf-cache-prefetch-delay 0.5 - "Idle time in seconds before prefetching images starts." - :group 'pdf-view - :type 'number) - -(defcustom pdf-cache-prefetch-pages-function - 'pdf-cache-prefetch-pages-function-default - "A function returning a list of pages to be prefetched. - -It is called with no arguments in the PDF window and should -return a list of page-numbers, determining the pages that should -be prefetched and their order." - :group 'pdf-view - :type 'function) - - -;; * ================================================================== * -;; * Simple Value cache -;; * ================================================================== * - -(defvar-local pdf-cache--data nil) - -(defvar pdf-annot-modified-functions) - -(defun pdf-cache--initialize () - (unless pdf-cache--data - (setq pdf-cache--data (make-hash-table)) - (add-hook 'pdf-info-close-document-hook 'pdf-cache-clear-data nil t) - (add-hook 'pdf-annot-modified-functions - 'pdf-cache--clear-data-of-annotations - nil t))) - -(defun pdf-cache--clear-data-of-annotations (fn) - (apply 'pdf-cache-clear-data-of-pages - (mapcar (lambda (a) - (cdr (assq 'page a))) - (funcall fn t)))) - -(defun pdf-cache--data-put (key value &optional page) - "Put KEY with VALUE in the cache of PAGE, return value." - (pdf-cache--initialize) - (puthash page (cons (cons key value) - (assq-delete-all - key - (gethash page pdf-cache--data))) - pdf-cache--data) - value) - -(defun pdf-cache--data-get (key &optional page) - "Get value of KEY in the cache of PAGE. - -Returns a cons \(HIT . VALUE\), where HIT is non-nil if KEY was -stored previously for PAGE and VALUE it's value. Otherwise HIT -is nil and VALUE undefined." - (pdf-cache--initialize) - (let ((elt (assq key (gethash page pdf-cache--data)))) - (if elt - (cons t (cdr elt)) - (cons nil nil)))) - -(defun pdf-cache--data-clear (key &optional page) - (pdf-cache--initialize) - (puthash page - (assq-delete-all key (gethash page pdf-cache--data)) - pdf-cache--data) - nil) - -(defun pdf-cache-clear-data-of-pages (&rest pages) - (when pdf-cache--data - (dolist (page pages) - (remhash page pdf-cache--data)))) - -(defun pdf-cache-clear-data () - (interactive) - (when pdf-cache--data - (clrhash pdf-cache--data))) - -(defmacro define-pdf-cache-function (command &optional page-arg-p) - "Define a simple data cache function. - -COMMAND is the name of the command, e.g. number-of-pages. It -should have a corresponding pdf-info function. If PAGE-ARG-P is -non-nil, define a one-dimensional cache indexed by the page -number. Otherwise the value is constant for each document, like -e.g. number-of-pages. - -Both args are unevaluated." - - (let ((args (if page-arg-p (list 'page))) - (fn (intern (format "pdf-cache-%s" command))) - (ifn (intern (format "pdf-info-%s" command))) - (doc (format "Cached version of `pdf-info-%s', which see. - -Make sure, not to modify it's return value." command))) - `(defun ,fn ,args - ,doc - (let ((hit-value (pdf-cache--data-get ',command ,(if page-arg-p 'page)))) - (if (car hit-value) - (cdr hit-value) - (pdf-cache--data-put - ',command - ,(if page-arg-p - (list ifn 'page) - (list ifn)) - ,(if page-arg-p 'page))))))) - -(define-pdf-cache-function pagelinks t) -(define-pdf-cache-function number-of-pages) -;; The boundingbox may change if annotations change. -(define-pdf-cache-function boundingbox t) -(define-pdf-cache-function textregions t) -(define-pdf-cache-function pagesize t) - - -;; * ================================================================== * -;; * PNG image LRU cache -;; * ================================================================== * - -(defvar pdf-cache-image-inihibit nil - "Non-nil, if the image cache should be bypassed.") - -(defvar-local pdf-cache--image-cache nil) - -(defmacro pdf-cache--make-image (page width data hash) - `(list ,page ,width ,data ,hash)) -(defmacro pdf-cache--image/page (img) `(nth 0 ,img)) -(defmacro pdf-cache--image/width (img) `(nth 1 ,img)) -(defmacro pdf-cache--image/data (img) `(nth 2 ,img)) -(defmacro pdf-cache--image/hash (img) `(nth 3 ,img)) - -(defun pdf-cache--image-match (image page min-width &optional max-width hash) - "Match IMAGE with specs. - -IMAGE should be a list as created by `pdf-cache--make-image'. - -Return non-nil, if IMAGE's page is the same as PAGE, it's width -is at least MIN-WIDTH and at most MAX-WIDTH and it's stored -hash-value is `eql' to HASH." - (and (= (pdf-cache--image/page image) - page) - (or (null min-width) - (>= (pdf-cache--image/width image) - min-width)) - (or (null max-width) - (<= (pdf-cache--image/width image) - max-width)) - (eql (pdf-cache--image/hash image) - hash))) - -(defun pdf-cache-lookup-image (page min-width &optional max-width hash) - "Return PAGE's cached PNG data as a string or nil. - -Does not modify the cache. See also `pdf-cache-get-image'." - (let ((image (car (cl-member - (list page min-width max-width hash) - pdf-cache--image-cache - :test (lambda (spec image) - (apply 'pdf-cache--image-match image spec)))))) - (and image - (pdf-cache--image/data image)))) - -(defun pdf-cache-get-image (page min-width &optional max-width hash) - "Return PAGE's PNG data as a string. - -Return an image of at least MIN-WIDTH and, if non-nil, maximum -width MAX-WIDTH and `eql' hash value. - -Remember that image was recently used. - -Returns nil, if no matching image was found." - (let ((cache pdf-cache--image-cache) - image) - ;; Find it in the cache. - (while (and (setq image (pop cache)) - (not (pdf-cache--image-match - image page min-width max-width hash)))) - ;; Remove it and push it to the front. - (when image - (setq pdf-cache--image-cache - (cons image (delq image pdf-cache--image-cache))) - (pdf-cache--image/data image)))) - -(defun pdf-cache-put-image (page width data &optional hash) - "Cache image of PAGE with WIDTH, DATA and HASH. - -DATA should the string of a PNG image of width WIDTH and from -page PAGE in the current buffer. See `pdf-cache-get-image' for -the HASH argument. - -This function always returns nil." - (unless pdf-cache--image-cache - (add-hook 'pdf-info-close-document-hook 'pdf-cache-clear-images nil t) - (add-hook 'pdf-annot-modified-functions - 'pdf-cache--clear-images-of-annotations nil t)) - (push (pdf-cache--make-image page width data hash) - pdf-cache--image-cache) - ;; Forget old image(s). - (when (> (length pdf-cache--image-cache) - pdf-cache-image-limit) - (if (> pdf-cache-image-limit 1) - (setcdr (nthcdr (1- pdf-cache-image-limit) - pdf-cache--image-cache) - nil) - (setq pdf-cache--image-cache nil))) - nil) - -(defun pdf-cache-clear-images () - "Clear the image cache." - (setq pdf-cache--image-cache nil)) - -(defun pdf-cache-clear-images-if (fn) - "Remove images from the cache according to FN. - -FN should be function accepting 4 Arguments \(PAGE WIDTH DATA -HASH\). It should return non-nil, if the image should be removed -from the cache." - (setq pdf-cache--image-cache - (cl-remove-if - (lambda (image) - (funcall - fn - (pdf-cache--image/page image) - (pdf-cache--image/width image) - (pdf-cache--image/data image) - (pdf-cache--image/hash image))) - pdf-cache--image-cache))) - - -(defun pdf-cache--clear-images-of-annotations (fn) - (apply 'pdf-cache-clear-images-of-pages - (mapcar (lambda (a) - (cdr (assq 'page a))) - (funcall fn t)))) - -(defun pdf-cache-clear-images-of-pages (&rest pages) - (pdf-cache-clear-images-if - (lambda (page &rest _) (memq page pages)))) - -(defun pdf-cache-renderpage (page min-width &optional max-width) - "Render PAGE according to MIN-WIDTH and MAX-WIDTH. - -Return the PNG data of an image as a string, such that it's width -is at least MIN-WIDTH and, if non-nil, at most MAX-WIDTH. - -If such an image is not available in the cache, call -`pdf-info-renderpage' to create one." - (if pdf-cache-image-inihibit - (pdf-info-renderpage page min-width) - (or (pdf-cache-get-image page min-width max-width) - (let ((data (pdf-info-renderpage page min-width))) - (pdf-cache-put-image page min-width data) - data)))) - -(defun pdf-cache-renderpage-text-regions (page width single-line-p - &rest selection) - "Render PAGE according to WIDTH, SINGLE-LINE-P and SELECTION. - -See also `pdf-info-renderpage-text-regions' and -`pdf-cache-renderpage'." - (if pdf-cache-image-inihibit - (apply 'pdf-info-renderpage-text-regions - page width single-line-p nil selection) - (let ((hash (sxhash - (format "%S" (cons 'renderpage-text-regions - (cons single-line-p selection)))))) - (or (pdf-cache-get-image page width width hash) - (let ((data (apply 'pdf-info-renderpage-text-regions - page width single-line-p nil selection))) - (pdf-cache-put-image page width data hash) - data))))) - -(defun pdf-cache-renderpage-highlight (page width &rest regions) - "Highlight PAGE according to WIDTH and REGIONS. - -See also `pdf-info-renderpage-highlight' and -`pdf-cache-renderpage'." - (if pdf-cache-image-inihibit - (apply 'pdf-info-renderpage-highlight - page width nil regions) - (let ((hash (sxhash - (format "%S" (cons 'renderpage-highlight - regions))))) - (or (pdf-cache-get-image page width width hash) - (let ((data (apply 'pdf-info-renderpage-highlight - page width nil regions))) - (pdf-cache-put-image page width data hash) - data))))) - - -;; * ================================================================== * -;; * Prefetching images -;; * ================================================================== * - -(defvar-local pdf-cache--prefetch-pages nil - "Pages to be prefetched.") - -(defvar-local pdf-cache--prefetch-timer nil - "Timer used when prefetching images.") - -(define-minor-mode pdf-cache-prefetch-minor-mode - "Try to load images which will probably be needed in a while." - nil nil nil - (pdf-cache--prefetch-cancel) - (cond - (pdf-cache-prefetch-minor-mode - (pdf-util-assert-pdf-buffer) - (add-hook 'pre-command-hook 'pdf-cache--prefetch-stop nil t) - ;; FIXME: Disable the time when the buffer is killed or it's - ;; major-mode changes. - (setq pdf-cache--prefetch-timer - (run-with-idle-timer (or pdf-cache-prefetch-delay 1) - t 'pdf-cache--prefetch-start (current-buffer)))) - (t - (remove-hook 'pre-command-hook 'pdf-cache--prefetch-stop t)))) - -(defun pdf-cache-prefetch-pages-function-default () - (let ((page (pdf-view-current-page))) - (pdf-util-remove-duplicates - (cl-remove-if-not - (lambda (page) - (and (>= page 1) - (<= page (pdf-cache-number-of-pages)))) - (append - ;; +1, -1, +2, -2, ... - (let ((sign 1) - (incr 1)) - (mapcar (lambda (_) - (setq page (+ page (* sign incr)) - sign (- sign) - incr (1+ incr)) - page) - (number-sequence 1 16))) - ;; First and last - (list 1 (pdf-cache-number-of-pages)) - ;; Links - (mapcar - (apply-partially 'alist-get 'page) - (cl-remove-if-not - (lambda (link) (eq (alist-get 'type link) 'goto-dest)) - (pdf-cache-pagelinks - (pdf-view-current-page))))))))) - -(defun pdf-cache--prefetch-pages (window image-width) - (when (and (eq window (selected-window)) - (pdf-util-pdf-buffer-p)) - (let ((page (pop pdf-cache--prefetch-pages))) - (while (and page - (pdf-cache-lookup-image - page - image-width - (if (not (pdf-view-use-scaling-p)) - image-width - (* 2 image-width)))) - (setq page (pop pdf-cache--prefetch-pages))) - (pdf-util-debug - (when (null page) - (message "Prefetching done."))) - (when page - (let* ((buffer (current-buffer)) - (pdf-info-asynchronous - (lambda (status data) - (when (and (null status) - (eq window - (selected-window)) - (eq buffer (window-buffer))) - (with-current-buffer (window-buffer) - (when (derived-mode-p 'pdf-view-mode) - (pdf-cache-put-image - page image-width data) - (image-size (pdf-view-create-page page)) - (pdf-util-debug - (message "Prefetched page %s." page)) - ;; Avoid max-lisp-eval-depth - (run-with-timer - 0.001 nil 'pdf-cache--prefetch-pages window image-width))))))) - (condition-case err - (pdf-info-renderpage page image-width) - (error - (pdf-cache-prefetch-minor-mode -1) - (signal (car err) (cdr err))))))))) - -(defvar pdf-cache--prefetch-started-p nil - "Guard against multiple prefetch starts. - -Used solely in `pdf-cache--prefetch-start'.") - -(defun pdf-cache--prefetch-start (buffer) - "Start prefetching images in BUFFER." - (when (and pdf-cache-prefetch-minor-mode - (not pdf-cache--prefetch-started-p) - (pdf-util-pdf-buffer-p) - (not isearch-mode) - (null pdf-cache--prefetch-pages) - (eq (window-buffer) buffer) - (fboundp pdf-cache-prefetch-pages-function)) - (let* ((pdf-cache--prefetch-started-p t) - (pages (funcall pdf-cache-prefetch-pages-function))) - (setq pdf-cache--prefetch-pages - (butlast pages (max 0 (- (length pages) - pdf-cache-image-limit)))) - (pdf-cache--prefetch-pages - (selected-window) - (car (pdf-view-desired-image-size)))))) - -(defun pdf-cache--prefetch-stop () - "Stop prefetching images in current buffer." - (setq pdf-cache--prefetch-pages nil)) - -(defun pdf-cache--prefetch-cancel () - "Cancel prefetching images in current buffer." - (pdf-cache--prefetch-stop) - (when pdf-cache--prefetch-timer - (cancel-timer pdf-cache--prefetch-timer)) - (setq pdf-cache--prefetch-timer nil)) - -(provide 'pdf-cache) -;;; pdf-cache.el ends here |