* shr.el (shr-tag-table): Render totally broken tables better.
[gnus] / lisp / shr.el
index 401ac1a..f49bbd6 100644 (file)
@@ -87,6 +87,18 @@ used."
 This is used for cid: URLs, and the function is called with the
 cid: URL as the argument.")
 
+(defvar shr-put-image-function 'shr-put-image
+  "Function called to put image and alt string.")
+
+(defface shr-strike-through '((t (:strike-through t)))
+  "Font for <s> elements."
+  :group 'shr)
+
+(defface shr-link
+  '((t (:inherit link)))
+  "Font for link elements."
+  :group 'shr)
+
 ;;; Internal variables.
 
 (defvar shr-folding-mode nil)
@@ -100,6 +112,7 @@ cid: URL as the argument.")
 (defvar shr-table-depth 0)
 (defvar shr-stylesheet nil)
 (defvar shr-base nil)
+(defvar shr-ignore-cache nil)
 
 (defvar shr-map
   (let ((map (make-sparse-keymap)))
@@ -171,14 +184,23 @@ redirects somewhere else."
        (message "No image under point")
       (message "%s" text))))
 
-(defun shr-browse-image ()
-  "Browse the image under point."
-  (interactive)
+(defun shr-browse-image (&optional copy-url)
+  "Browse the image under point.
+If COPY-URL (the prefix if called interactively) is non-nil, copy
+the URL of the image to the kill buffer instead."
+  (interactive "P")
   (let ((url (get-text-property (point) 'image-url)))
-    (if (not url)
-       (message "No image under point")
+    (cond
+     ((not url)
+      (message "No image under point"))
+     (copy-url
+      (with-temp-buffer
+       (insert url)
+       (copy-region-as-kill (point-min) (point-max))
+       (message "Copied %s" url)))
+     (t
       (message "Browsing %s..." url)
-      (browse-url url))))
+      (browse-url url)))))
 
 (defun shr-insert-image ()
   "Insert the image under point into the buffer."
@@ -491,10 +513,11 @@ redirects somewhere else."
                  (inhibit-read-only t))
              (delete-region start end)
              (goto-char start)
-             (shr-put-image data alt)))))))
+             (funcall shr-put-image-function data alt)))))))
   (kill-buffer (current-buffer)))
 
 (defun shr-put-image (data alt)
+  "Put image DATA with a string ALT.  Return image."
   (if (display-graphic-p)
       (let ((image (ignore-errors
                      (shr-rescale-image data))))
@@ -504,14 +527,18 @@ redirects somewhere else."
          (when (and (> (current-column) 0)
                     (> (car (image-size image t)) 400))
            (insert "\n"))
-         (insert-image image (or alt "*"))))
+         (insert-image image (or alt "*"))
+         (when (image-animated-p image)
+           (image-animate image nil 60)))
+       image)
     (insert alt)))
 
 (defun shr-rescale-image (data)
   (if (or (not (fboundp 'imagemagick-types))
          (not (get-buffer-window (current-buffer))))
-      (create-image data nil t)
-    (let* ((image (create-image data nil t))
+      (create-image data nil t
+                   :ascent 100)
+    (let* ((image (create-image data nil t :ascent 100))
           (size (image-size image t))
           (width (car size))
           (height (cdr size))
@@ -530,11 +557,9 @@ redirects somewhere else."
       (when (> (car size) window-width)
        (setq image (or
                     (create-image data 'imagemagick t
-                                  :width window-width)
+                                  :width window-width
+                                  :ascent 100)
                     image)))
-      (when (and (fboundp 'create-animated-image)
-                (eq (image-type data nil t) 'gif))
-       (setq image (create-animated-image data 'gif t)))
       image)))
 
 ;; url-cache-extract autoloads url-cache.
@@ -567,8 +592,8 @@ START, and END.  Note that START and END should be merkers."
                                     (substring url (match-end 0)))))
                 (when image
                   (goto-char start)
-                  (shr-put-image image
-                                 (buffer-substring-no-properties start end))
+                  (funcall shr-put-image-function
+                           image (buffer-substring start end))
                   (delete-region (point) end))))
         (url-retrieve url 'shr-image-fetched
                       (list (current-buffer) start end)
@@ -587,6 +612,7 @@ START, and END.  Note that START and END should be merkers."
    :help-echo (if title (format "%s (%s)" url title) url)
    :keymap shr-map
    url)
+  (shr-add-font start (point) 'shr-link)
   (put-text-property start (point) 'shr-url url))
 
 (defun shr-encode-url (url)
@@ -628,7 +654,7 @@ ones, in case fg and bg are nil."
          (shr-put-color start end :background (car new-colors))))
       new-colors)))
 
-;; Put a color in the region, but avoid putting colors on on blank
+;; Put a color in the region, but avoid putting colors on blank
 ;; text at the start of the line, and the newline at the end, to avoid
 ;; ugliness.  Also, don't overwrite any existing color information,
 ;; since this can be called recursively, and we want the "inner" color
@@ -701,7 +727,8 @@ ones, in case fg and bg are nil."
 
 (defun shr-put-color-1 (start end type color)
   (let* ((old-props (get-text-property start 'face))
-        (do-put (not (memq type old-props)))
+        (do-put (and (listp old-props)
+                      (not (memq type old-props))))
         change)
     (while (< start end)
       (setq change (next-single-property-change start 'face nil end))
@@ -709,7 +736,8 @@ ones, in case fg and bg are nil."
        (put-text-property start change 'face
                           (nconc (list type color) old-props)))
       (setq old-props (get-text-property change 'face))
-      (setq do-put (not (memq type old-props)))
+      (setq do-put (and (listp old-props)
+                        (not (memq type old-props))))
       (setq start change))
     (when (and do-put
               (> end start))
@@ -734,6 +762,19 @@ ones, in case fg and bg are nil."
 (defun shr-tag-script (cont)
   )
 
+(defun shr-tag-comment (cont)
+  )
+
+(defun shr-tag-sup (cont)
+  (let ((start (point)))
+    (shr-generic cont)
+    (put-text-property start (point) 'display '(raise 0.5))))
+
+(defun shr-tag-sub (cont)
+  (let ((start (point)))
+    (shr-generic cont)
+    (put-text-property start (point) 'display '(raise -0.5))))
+
 (defun shr-tag-label (cont)
   (shr-generic cont)
   (shr-ensure-paragraph))
@@ -750,6 +791,12 @@ ones, in case fg and bg are nil."
   (shr-generic cont)
   (shr-ensure-newline))
 
+(defun shr-tag-s (cont)
+  (shr-fontize-cont cont 'shr-strike-through))
+
+(defun shr-tag-del (cont)
+  (shr-fontize-cont cont 'shr-strike-through))
+
 (defun shr-tag-b (cont)
   (shr-fontize-cont cont 'bold))
 
@@ -765,9 +812,6 @@ ones, in case fg and bg are nil."
 (defun shr-tag-u (cont)
   (shr-fontize-cont cont 'underline))
 
-(defun shr-tag-s (cont)
-  (shr-fontize-cont cont 'strike-through))
-
 (defun shr-parse-style (style)
   (when style
     (save-match-data
@@ -844,7 +888,7 @@ ones, in case fg and bg are nil."
            (if (or (not shr-content-function)
                    (not (setq image (funcall shr-content-function url))))
                (insert alt)
-             (shr-put-image image alt))))
+             (funcall shr-put-image-function image alt))))
         ((or shr-inhibit-images
              (and shr-blocked-images
                   (string-match shr-blocked-images url)))
@@ -853,14 +897,23 @@ ones, in case fg and bg are nil."
            (if (> (string-width alt) 8)
                (shr-insert (truncate-string-to-width alt 8))
              (shr-insert alt))))
-        ((url-is-cached (shr-encode-url url))
-         (shr-put-image (shr-get-image-data url) alt))
+        ((and (not shr-ignore-cache)
+              (url-is-cached (shr-encode-url url)))
+         (funcall shr-put-image-function (shr-get-image-data url) alt))
         (t
          (insert alt)
-         (ignore-errors
-           (url-retrieve (shr-encode-url url) 'shr-image-fetched
-                         (list (current-buffer) start (point-marker))
-                         t))))
+         (when (and shr-ignore-cache
+                    (url-is-cached (shr-encode-url url)))
+           (let ((file (url-cache-create-filename (shr-encode-url url))))
+             (when (file-exists-p file)
+               (delete-file file))))
+         (funcall
+          (if (fboundp 'url-queue-retrieve)
+              'url-queue-retrieve
+            'url-retrieve)
+          (shr-encode-url url) 'shr-image-fetched
+          (list (current-buffer) start (point-marker))
+          t)))
        (put-text-property start (point) 'keymap shr-map)
        (put-text-property start (point) 'shr-alt alt)
        (put-text-property start (point) 'image-url url)
@@ -1002,44 +1055,53 @@ ones, in case fg and bg are nil."
         (nheader (if header (shr-max-columns header)))
         (nbody (if body (shr-max-columns body)))
         (nfooter (if footer (shr-max-columns footer))))
-    (shr-tag-table-1
-     (nconc
-      (if caption `((tr (td ,@caption))))
-      (if header
-         (if footer
-             ;; hader + body + footer
+    (if (and (not caption)
+            (not header)
+            (not (cdr (assq 'tbody cont)))
+            (not (cdr (assq 'tr cont)))
+            (not footer))
+       ;; The table is totally invalid and just contains random junk.
+       ;; Try to output it anyway.
+       (shr-generic cont)
+      ;; It's a real table, so render it.
+      (shr-tag-table-1
+       (nconc
+       (if caption `((tr (td ,@caption))))
+       (if header
+           (if footer
+               ;; hader + body + footer
+               (if (= nheader nbody)
+                   (if (= nbody nfooter)
+                       `((tr (td (table (tbody ,@header ,@body ,@footer)))))
+                     (nconc `((tr (td (table (tbody ,@header ,@body)))))
+                            (if (= nfooter 1)
+                                footer
+                              `((tr (td (table (tbody ,@footer))))))))
+                 (nconc `((tr (td (table (tbody ,@header)))))
+                        (if (= nbody nfooter)
+                            `((tr (td (table (tbody ,@body ,@footer)))))
+                          (nconc `((tr (td (table (tbody ,@body)))))
+                                 (if (= nfooter 1)
+                                     footer
+                                   `((tr (td (table (tbody ,@footer))))))))))
+             ;; header + body
              (if (= nheader nbody)
-                 (if (= nbody nfooter)
-                     `((tr (td (table (tbody ,@header ,@body ,@footer)))))
-                   (nconc `((tr (td (table (tbody ,@header ,@body)))))
-                          (if (= nfooter 1)
-                              footer
-                            `((tr (td (table (tbody ,@footer))))))))
-               (nconc `((tr (td (table (tbody ,@header)))))
-                      (if (= nbody nfooter)
-                          `((tr (td (table (tbody ,@body ,@footer)))))
-                        (nconc `((tr (td (table (tbody ,@body)))))
-                               (if (= nfooter 1)
-                                   footer
-                                 `((tr (td (table (tbody ,@footer))))))))))
-           ;; header + body
-           (if (= nheader nbody)
-               `((tr (td (table (tbody ,@header ,@body)))))
-             (if (= nheader 1)
-                 `(,@header (tr (td (table (tbody ,@body)))))
-               `((tr (td (table (tbody ,@header))))
-                 (tr (td (table (tbody ,@body))))))))
-       (if footer
-           ;; body + footer
-           (if (= nbody nfooter)
-               `((tr (td (table (tbody ,@body ,@footer)))))
-             (nconc `((tr (td (table (tbody ,@body)))))
-                    (if (= nfooter 1)
-                        footer
-                      `((tr (td (table (tbody ,@footer))))))))
-         (if caption
-             `((tr (td (table (tbody ,@body)))))
-           body)))))
+                 `((tr (td (table (tbody ,@header ,@body)))))
+               (if (= nheader 1)
+                   `(,@header (tr (td (table (tbody ,@body)))))
+                 `((tr (td (table (tbody ,@header))))
+                   (tr (td (table (tbody ,@body))))))))
+         (if footer
+             ;; body + footer
+             (if (= nbody nfooter)
+                 `((tr (td (table (tbody ,@body ,@footer)))))
+               (nconc `((tr (td (table (tbody ,@body)))))
+                      (if (= nfooter 1)
+                          footer
+                        `((tr (td (table (tbody ,@footer))))))))
+           (if caption
+               `((tr (td (table (tbody ,@body)))))
+             body))))))
     (when bgcolor
       (shr-colorize-region start (point) (cdr (assq 'color shr-stylesheet))
                           bgcolor))))