aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ingebrigtsen2016-02-20 18:01:52 +1100
committerLars Ingebrigtsen2016-02-20 18:03:37 +1100
commit80852f843e69b81618f29cfb9aa4b074946cb3c4 (patch)
tree23febac62f733f568afaf9ddec54ce3f7745b760
parentad1951dbfb7e289553c25474efdfa02f83c16e71 (diff)
downloademacs-80852f843e69b81618f29cfb9aa4b074946cb3c4.tar.gz
emacs-80852f843e69b81618f29cfb9aa4b074946cb3c4.zip
Use placeholder images in shr to avoid text moving around
* lisp/net/shr.el (shr-rescale-image): Pass in width/height from the HTML. (shr-tag-img): Ditto. (shr-string-number): New function. (shr-make-placeholder-image): Make placeholder images. (shr-tag-img): Insert them if we have SVG support.
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/net/shr.el111
2 files changed, 99 insertions, 19 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 95ca8d35385..33c1b136ebc 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -779,6 +779,13 @@ textual parts of a web page and display only that, leaving menus and
779the like off the page. 779the like off the page.
780 780
781--- 781---
782*** Images that are being loaded are now marked with grey
783"placeholder" images of the size specified by the HTML. They are then
784replaced by the real images asynchronously, which will also now
785respect width/height HTML specs (unless they specify widths/heights
786bigger than the current window).
787
788---
782*** You can now use several eww buffers in parallel by renaming eww 789*** You can now use several eww buffers in parallel by renaming eww
783buffers you want to keep separate. 790buffers you want to keep separate.
784 791
diff --git a/lisp/net/shr.el b/lisp/net/shr.el
index 46aea79c327..78862b373d4 100644
--- a/lisp/net/shr.el
+++ b/lisp/net/shr.el
@@ -36,6 +36,7 @@
36(require 'subr-x) 36(require 'subr-x)
37(require 'dom) 37(require 'dom)
38(require 'seq) 38(require 'seq)
39(require 'svg)
39 40
40(defgroup shr nil 41(defgroup shr nil
41 "Simple HTML Renderer" 42 "Simple HTML Renderer"
@@ -963,10 +964,14 @@ element is the data blob and the second element is the content-type."
963 (create-image data 'svg t :ascent 100)) 964 (create-image data 'svg t :ascent 100))
964 ((eq size 'full) 965 ((eq size 'full)
965 (ignore-errors 966 (ignore-errors
966 (shr-rescale-image data content-type))) 967 (shr-rescale-image data content-type
968 (plist-get flags :width)
969 (plist-get flags :height))))
967 (t 970 (t
968 (ignore-errors 971 (ignore-errors
969 (shr-rescale-image data content-type)))))) 972 (shr-rescale-image data content-type
973 (plist-get flags :width)
974 (plist-get flags :height)))))))
970 (when image 975 (when image
971 ;; When inserting big-ish pictures, put them at the 976 ;; When inserting big-ish pictures, put them at the
972 ;; beginning of the line. 977 ;; beginning of the line.
@@ -989,21 +994,37 @@ element is the data blob and the second element is the content-type."
989 image) 994 image)
990 (insert (or alt "")))) 995 (insert (or alt ""))))
991 996
992(defun shr-rescale-image (data &optional content-type) 997(defun shr-rescale-image (data content-type width height)
993 "Rescale DATA, if too big, to fit the current buffer." 998 "Rescale DATA, if too big, to fit the current buffer.
999WIDTH and HEIGHT are the sizes given in the HTML data, if any."
994 (if (not (and (fboundp 'imagemagick-types) 1000 (if (not (and (fboundp 'imagemagick-types)
995 (get-buffer-window (current-buffer)))) 1001 (get-buffer-window (current-buffer))))
996 (create-image data nil t :ascent 100) 1002 (create-image data nil t :ascent 100)
997 (let ((edges (window-inside-pixel-edges 1003 (let* ((edges (window-inside-pixel-edges
998 (get-buffer-window (current-buffer))))) 1004 (get-buffer-window (current-buffer))))
999 (create-image 1005 (max-width (truncate (* shr-max-image-proportion
1000 data 'imagemagick t 1006 (- (nth 2 edges) (nth 0 edges)))))
1001 :ascent 100 1007 (max-height (truncate (* shr-max-image-proportion
1002 :max-width (truncate (* shr-max-image-proportion 1008 (- (nth 3 edges) (nth 1 edges))))))
1003 (- (nth 2 edges) (nth 0 edges)))) 1009 (when (or (and width
1004 :max-height (truncate (* shr-max-image-proportion 1010 (> width max-width))
1005 (- (nth 3 edges) (nth 1 edges)))) 1011 (and height
1006 :format content-type)))) 1012 (> height max-height)))
1013 (setq width nil
1014 height nil))
1015 (if (and width height)
1016 (create-image
1017 data 'imagemagick t
1018 :ascent 100
1019 :width width
1020 :height height
1021 :format content-type)
1022 (create-image
1023 data 'imagemagick t
1024 :ascent 100
1025 :max-width max-width
1026 :max-height max-height
1027 :format content-type)))))
1007 1028
1008;; url-cache-extract autoloads url-cache. 1029;; url-cache-extract autoloads url-cache.
1009(declare-function url-cache-create-filename "url-cache" (url)) 1030(declare-function url-cache-create-filename "url-cache" (url))
@@ -1427,6 +1448,8 @@ The preference is a float determined from `shr-prefer-media-type'."
1427 (when (> (current-column) 0) 1448 (when (> (current-column) 0)
1428 (insert "\n")) 1449 (insert "\n"))
1429 (let ((alt (dom-attr dom 'alt)) 1450 (let ((alt (dom-attr dom 'alt))
1451 (width (shr-string-number (dom-attr dom 'width)))
1452 (height (shr-string-number (dom-attr dom 'height)))
1430 (url (shr-expand-url (or url (dom-attr dom 'src))))) 1453 (url (shr-expand-url (or url (dom-attr dom 'src)))))
1431 (let ((start (point-marker))) 1454 (let ((start (point-marker)))
1432 (when (zerop (length alt)) 1455 (when (zerop (length alt))
@@ -1440,7 +1463,8 @@ The preference is a float determined from `shr-prefer-media-type'."
1440 (string-match "\\`data:" url)) 1463 (string-match "\\`data:" url))
1441 (let ((image (shr-image-from-data (substring url (match-end 0))))) 1464 (let ((image (shr-image-from-data (substring url (match-end 0)))))
1442 (if image 1465 (if image
1443 (funcall shr-put-image-function image alt) 1466 (funcall shr-put-image-function image alt
1467 (list :width width :height height))
1444 (insert alt)))) 1468 (insert alt))))
1445 ((and (not shr-inhibit-images) 1469 ((and (not shr-inhibit-images)
1446 (string-match "\\`cid:" url)) 1470 (string-match "\\`cid:" url))
@@ -1449,7 +1473,8 @@ The preference is a float determined from `shr-prefer-media-type'."
1449 (if (or (not shr-content-function) 1473 (if (or (not shr-content-function)
1450 (not (setq image (funcall shr-content-function url)))) 1474 (not (setq image (funcall shr-content-function url))))
1451 (insert alt) 1475 (insert alt)
1452 (funcall shr-put-image-function image alt)))) 1476 (funcall shr-put-image-function image alt
1477 (list :width width :height height)))))
1453 ((or shr-inhibit-images 1478 ((or shr-inhibit-images
1454 (and shr-blocked-images 1479 (and shr-blocked-images
1455 (string-match shr-blocked-images url))) 1480 (string-match shr-blocked-images url)))
@@ -1457,17 +1482,23 @@ The preference is a float determined from `shr-prefer-media-type'."
1457 (shr-insert alt)) 1482 (shr-insert alt))
1458 ((and (not shr-ignore-cache) 1483 ((and (not shr-ignore-cache)
1459 (url-is-cached (shr-encode-url url))) 1484 (url-is-cached (shr-encode-url url)))
1460 (funcall shr-put-image-function (shr-get-image-data url) alt)) 1485 (funcall shr-put-image-function (shr-get-image-data url) alt
1486 (list :width width :height height)))
1461 (t 1487 (t
1462 (insert alt " ")
1463 (when (and shr-ignore-cache 1488 (when (and shr-ignore-cache
1464 (url-is-cached (shr-encode-url url))) 1489 (url-is-cached (shr-encode-url url)))
1465 (let ((file (url-cache-create-filename (shr-encode-url url)))) 1490 (let ((file (url-cache-create-filename (shr-encode-url url))))
1466 (when (file-exists-p file) 1491 (when (file-exists-p file)
1467 (delete-file file)))) 1492 (delete-file file))))
1493 (when (image-type-available-p 'svg)
1494 (insert-image
1495 (shr-make-placeholder-image dom)
1496 (or alt "")))
1497 (insert " ")
1468 (url-queue-retrieve 1498 (url-queue-retrieve
1469 (shr-encode-url url) 'shr-image-fetched 1499 (shr-encode-url url) 'shr-image-fetched
1470 (list (current-buffer) start (set-marker (make-marker) (1- (point)))) 1500 (list (current-buffer) start (set-marker (make-marker) (1- (point)))
1501 (list :width width :height height))
1471 t t))) 1502 t t)))
1472 (when (zerop shr-table-depth) ;; We are not in a table. 1503 (when (zerop shr-table-depth) ;; We are not in a table.
1473 (put-text-property start (point) 'keymap shr-image-map) 1504 (put-text-property start (point) 'keymap shr-image-map)
@@ -1479,6 +1510,48 @@ The preference is a float determined from `shr-prefer-media-type'."
1479 (shr-fill-text 1510 (shr-fill-text
1480 (or (dom-attr dom 'title) alt)))))))) 1511 (or (dom-attr dom 'title) alt))))))))
1481 1512
1513(defun shr-string-number (string)
1514 (if (null string)
1515 nil
1516 (setq string (replace-regexp-in-string "[^0-9]" "" string))
1517 (if (zerop (length string))
1518 nil
1519 (string-to-number string))))
1520
1521(defun shr-make-placeholder-image (dom)
1522 (let* ((edges (and
1523 (get-buffer-window (current-buffer))
1524 (window-inside-pixel-edges
1525 (get-buffer-window (current-buffer)))))
1526 (scaling (image-compute-scaling-factor image-scaling-factor))
1527 (width (truncate
1528 (* (or (shr-string-number (dom-attr dom 'width)) 100)
1529 scaling)))
1530 (height (truncate
1531 (* (or (shr-string-number (dom-attr dom 'height)) 100)
1532 scaling)))
1533 (max-width
1534 (and edges
1535 (truncate (* shr-max-image-proportion
1536 (- (nth 2 edges) (nth 0 edges))))))
1537 (max-height (and edges
1538 (truncate (* shr-max-image-proportion
1539 (- (nth 3 edges) (nth 1 edges))))))
1540 svg image)
1541 (when (and max-width
1542 (> width max-width))
1543 (setq height (truncate (* (/ (float max-width) width) height))
1544 width max-width))
1545 (when (and max-height
1546 (> height max-height))
1547 (setq width (truncate (* (/ (float max-height) height) width))
1548 height max-height))
1549 (setq svg (svg-create width height))
1550 (svg-gradient svg "background" 'linear '((0 . "#b0b0b0") (100 . "#808080")))
1551 (svg-rectangle svg 0 0 width height :gradient "background")
1552 (let ((image (svg-image svg)))
1553 (image-set-property image :ascent 100))))
1554
1482(defun shr-tag-pre (dom) 1555(defun shr-tag-pre (dom)
1483 (let ((shr-folding-mode 'none) 1556 (let ((shr-folding-mode 'none)
1484 (shr-current-font 'default)) 1557 (shr-current-font 'default))