Mercurial > hg > xemacs-beta
diff lisp/w3/w3-style.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/w3/w3-style.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,522 @@ +;;; w3-style.el,v --- Emacs-W3 binding style sheet mechanism +;; Author: wmperry +;; Created: 1996/05/31 21:34:16 +;; Version: 1.82 +;; Keywords: faces, hypermedia + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Copyright (c) 1993, 1994, 1995 by William M. Perry (wmperry@spry.com) +;;; +;;; This file is not part of GNU Emacs, but the same permissions apply. +;;; +;;; GNU Emacs 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 2, or (at your option) +;;; any later version. +;;; +;;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to +;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; A style sheet mechanism for emacs-w3 +;;; +;;; This will eventually be able to under DSSSL[-lite] as well as the +;;; experimental W3C mechanism +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(require 'font) +(require 'w3-keyword) +(require 'cl) + +(defvar w3-style-css-syntax-table + (copy-syntax-table mm-parse-args-syntax-table) + "The syntax table for parsing stylesheets") + +(defvar w3-style-ie-compatibility nil + "*Whether we want to do Internet Explorer 3.0 compatible parsing of +CSS stylesheets.") + +(defun w3-style-css-parse-args (st &optional nd defines) + ;; Return an assoc list of attribute/value pairs from a CSS style entry + (let ( + name ; From name= + value ; its value + results ; Assoc list of results + name-pos ; Start of XXXX= position + val-pos ; Start of value position + ) + (save-excursion + (if (stringp st) + (progn + (set-buffer (get-buffer-create " *w3-style-temp*")) + (set-syntax-table w3-style-css-syntax-table) + (erase-buffer) + (insert st) + (setq st (point-min) + nd (point-max))) + (set-syntax-table w3-style-css-syntax-table)) + (save-restriction + (if (< nd st) + (narrow-to-region nd nd) + (narrow-to-region st nd)) + (goto-char (point-min)) + (while (not (eobp)) + (skip-chars-forward ";, \n\t") + (setq name-pos (point)) + (skip-chars-forward "^ \n\t:=,;") + (downcase-region name-pos (point)) + (setq name (buffer-substring name-pos (point))) + (skip-chars-forward " \t\n") + (if (not (eq (char-after (point)) ?:)) ; There is no value + (setq value nil) + (skip-chars-forward " \t\n:") + (setq val-pos (point) + value + (cond + ((or (= (or (char-after val-pos) 0) ?\") + (= (or (char-after val-pos) 0) ?')) + (buffer-substring (1+ val-pos) + (condition-case () + (prog2 + (forward-sexp 1) + (1- (point)) + (skip-chars-forward "\"")) + (error + (skip-chars-forward "^ \t\n") + (point))))) + (t + (buffer-substring val-pos + (progn + (if w3-style-ie-compatibility + (skip-chars-forward "^;") + (skip-chars-forward "^,;")) + (skip-chars-backward " \t") + (point))))))) + (setq results (cons (cons name value) results)) + (skip-chars-forward ";, \n\t")) + results)))) + +(defvar w3-style-css-define-table nil) + +(defun w3-style-css-handle-define () + (let ((name nil) + (save-pos (point)) + (retval nil)) + (skip-chars-forward "^ \t\r\n") ; Past the name token + (downcase-region save-pos (point)) + (setq name (buffer-substring save-pos (point))) + (skip-chars-forward "= \t\r") + (setq save-pos (point)) + (skip-chars-forward "^;") + (setq retval (cons name (buffer-substring save-pos (point)))) + (skip-chars-forward " \t\r\n") + retval)) + +(defun w3-style-css-handle-import () + (let ((url nil) + (save-pos (point))) + (if (looking-at "'\"") + (condition-case () + (forward-sexp 1) + (error (skip-chars-forward "^ \t\r\n;"))) + (skip-chars-forward "^ \t\r\n;")) + (setq url (url-expand-file-name (buffer-substring save-pos (point)))) + (skip-chars-forward "\"; \t\r\n") + (setq save-pos (point)) + (let ((url-working-buffer (url-generate-new-buffer-name " *styleimport*")) + (url-mime-accept-string + "text/css ; level=2") + (sheet nil)) + (save-excursion + (set-buffer (get-buffer-create url-working-buffer)) + (setq url-be-asynchronous nil) + (url-retrieve url) + (w3-style-css-clean) + (setq sheet (buffer-string)) + (kill-buffer (current-buffer))) + (insert sheet) + (goto-char save-pos)))) + +(defun w3-style-css-clean () + ;; Nuke comments, etc. + (goto-char (point-min)) + (let ((save-pos nil)) + (while (search-forward "/*" nil t) + (setq save-pos (- (point) 2)) + (delete-region save-pos + (if (search-forward "*/" nil t) + (point) + (end-of-line) + (point))))) + (goto-char (point-min)) + (delete-matching-lines "^[ \t\r]*$") ; Nuke blank lines + (w3-replace-regexp "^[ \t\r]+" "") ; Nuke whitespace at beg. of line + (w3-replace-regexp "[ \t\r]+$" "") ; Nuke whitespace at end of line + (goto-char (point-min))) + +(defun w3-style-css-applies-to (st nd) + (let ((results nil) + (save-pos nil)) + (narrow-to-region st nd) + (goto-char st) + (skip-chars-forward " \t\r\n") + (while (not (eobp)) + (setq save-pos (point)) + (skip-chars-forward "^,") + (skip-chars-backward " \r\t\n") + (setq results (cons (buffer-substring save-pos (point)) results)) + (skip-chars-forward ", \t\r\n")) + (widen) + results)) + +(defun w3-style-parse-css (fname &optional string inherit) + (let ( + (url-mime-accept-string + "text/css ; level=2") + (save-pos nil) + (applies-to nil) ; List of tags to apply style to + (attrs nil) ; List of name/value pairs + (tag nil) + (att nil) + (cur nil) + (val nil) + (class nil) + (defines nil) + (device-type nil) + (active-device-types (list 'normal 'default + (if w3-running-FSF19 'emacs 'xemacs))) + (sheet inherit)) + (let ((type (device-type))) + (cond + ((eq type 'tty) + (if (and (fboundp 'tty-color-list) + (/= 0 (length (tty-color-list)))) + (setq active-device-types (cons 'ansi-tty active-device-types)) + (setq active-device-types (cons 'tty active-device-types)))) + ((eq 'color (device-class)) + (setq active-device-types + (append + (list (intern (format "%dbit-color" + (device-bitplanes))) + (intern (format "%dbit" + (device-bitplanes))) + 'color) active-device-types)) + (if (= 24 (device-bitplanes)) + (setq active-device-types (cons 'truecolor active-device-types)))) + ((eq 'grayscale (device-class)) + (setq active-device-types (append + (list (intern (format "%dbit-grayscale" + (device-bitplanes))) + 'grayscale) + active-device-types))) + ((eq 'mono (device-class)) + (setq active-device-types (append (list 'mono 'monochrome) + active-device-types))) + (t + (setq active-device-types (cons 'unknown active-device-types))))) + + (save-excursion + (set-buffer (get-buffer-create + (url-generate-new-buffer-name " *style*"))) + (set-syntax-table w3-style-css-syntax-table) + (erase-buffer) + (if fname (url-insert-file-contents fname)) + (goto-char (point-max)) + (if string (insert string)) + (w3-style-css-clean) + (goto-char (point-min)) + (while (not (eobp)) + (setq save-pos (point)) + (cond + ;; C++ style comments, and we are doing IE compatibility + ((and (looking-at "//") w3-style-ie-compatibility) + (end-of-line)) + ;; Pre-Processor directives + ((looking-at "[ \t\r]*@\\([^ \t\r\n]\\)") + (let ((directive nil)) + (skip-chars-forward " @\t\r") ; Past any leading whitespace + (setq save-pos (point)) + (skip-chars-forward "^ \t\r\n") ; Past the @ directive + (downcase-region save-pos (point)) + (setq directive (buffer-substring save-pos (point))) + (skip-chars-forward " \t\r") ; Past any trailing whitespace + (setq save-pos (point)) + (cond + ((string= directive "define") + (let ((retval (w3-style-css-handle-define))) + (and defines + (setq defines (cons retval defines))))) + ((string= directive "import") + (w3-style-css-handle-import)) + (t + (w3-warn 'style (format "Unknown directive: @%s" directive) + 'warning))))) + ;; Giving us some output device information + ((looking-at "[ \t\r]*:\\([^:]+\\):") + (downcase-region (match-beginning 1) (match-end 1)) + (setq device-type (intern (buffer-substring (match-beginning 1) + (match-end 1)))) + (goto-char (match-end 0)) + (if (not (memq device-type active-device-types)) + ;; Not applicable to us... skip the info + (progn + (if (re-search-forward ":[^:]*:" nil t) + (goto-char (match-beginning 0)) + (goto-char (point-max)))))) + ;; Default is to treat it like a stylesheet declaration + (t + (skip-chars-forward "^{:") + (downcase-region save-pos (point)) + (setq applies-to (w3-style-css-applies-to save-pos (point))) + (skip-chars-forward "^{") + (setq save-pos (point)) + (forward-sexp 1) + (end-of-line) + (skip-chars-backward "\r}") + (subst-char-in-region save-pos (point) ?\n ? ) + (subst-char-in-region save-pos (point) ?\r ? ) + (setq attrs (w3-style-css-parse-args (1+ save-pos) + (point) defines)) + (skip-chars-forward "}\r\n") + (while applies-to + (setq cur (car applies-to) + applies-to (cdr applies-to)) + (cond + ((string-match "\\(.*\\)\\.\\(.*\\)" cur) ; Normal class + (setq tag (intern (downcase (match-string 1 cur))) + class (match-string 2 cur))) + ((string-match "\\(.*\\):\\(.*\\)" cur) ; Pseudo class + (setq tag (intern (downcase (match-string 1 cur))) + class (match-string 2 cur))) + (t ; No class - global + (setq tag (intern (downcase cur)) + class 'internal))) + (let ((loop attrs)) + (while loop + (if (stringp (car (car loop))) + (setcar (car loop) (intern (car (car loop))))) + (setq att (car (car loop)) + val (cdr (car loop)) + loop (cdr loop)) + (case att + ((align textalign text-align display white-space) + (setq val (intern (downcase val)))) + ((indent left-margin right-margin top-margin bottom-margin) + (setq val (string-to-int val))) + (otherwise + nil)) + (let* ((node-1 (assq tag sheet)) + (node-2 (and node-1 (assoc class node-1))) + (node-3 (and node-2 (assq att node-2)))) + (cond + ((not node-1) ; New top-level element + (setq sheet (cons (cons tag (list (cons class + (list + (cons att val))))) + sheet))) + ((and node-1 (not node-2)) ; New class for existing element + (setcdr node-1 (cons (cons class (list (cons att val))) + (cdr node-1)))) + ((and node-2 (not node-3)) ; attribute/value on old class + (setcdr node-2 (cons (cons att val) (cdr node-2)))) + (node-3 ; Replace existing attribute value + (setcdr node-3 val))))))))) + (skip-chars-forward " \t\r\n")) + (set-buffer-modified-p nil) + (kill-buffer (current-buffer))) + (cons sheet defines))) + + +(defvar w3-style-font-size-mappings + '(("xx-small" . 0) + ("x-small" . 1) + ("small" . 2) + ("medium" . 3) + ("large" . 4) + ("x-large" . 5) + ("xx-large" . 6) + ) + "A list of font size mappings") + +(defvar w3-style-font-weight-mappings + '(("-3" . :extra-light) + ("-2" . :light) + ("-1" . :demi-light) + ("0" . :medium) + ("1" . :normal) + ("2" . :demi-bold) + ("3" . :bold) + ("4" . :extrabold) + ("bold" . :bold) + ("demi-light" . :demi-light) + ("demi-bold" . :demi-bold) + ("extra-bold" . :extra-bold) + ("extra-light". :extra-light) + ) + "A list of font weight mappings.") + +(defun w3-style-font-size-for-index (index) + (if (stringp index) + (setq index (or + (cdr-safe (assoc (downcase index) + w3-style-font-size-mappings)) + 3))) + (setq index (- index 3)) + (let ((scaler (if (> index 0) + 1.44 + 0.695)) + (size 12)) + (setq index (abs index)) + (while (/= index 0) + (setq size (* size scaler) + index (1- index))) + ;; This rounds to the nearest '10' + (format "%dpt" (* 10 (round (/ size 10)))))) + +(defun w3-generate-stylesheet-faces (sheet) + (let ((todo sheet) + (cur nil) + (cur-classes nil) + (node nil) + (voice nil) + (voice-person nil) + (voice-tone nil) + (fore nil) + (back nil) + (pixmap nil) + (font nil) + (family nil) + (decoration nil) + (style nil) + (size nil) + (index nil) + (shorthand nil) + (weight nil) + (break-style nil)) + (while todo + (setq cur (car todo) + cur-classes (cdr cur) + todo (cdr todo)) + (while cur-classes + (setq node (cdr (car cur-classes)) + cur (car cur-classes) + cur-classes (cdr cur-classes) + fore (cdr-safe (assq 'color node)) + back (cdr-safe (assq 'background node)) + voice-person (cdr-safe (assq 'voice node)) + voice-tone (cdr-safe (assq 'voice-tone node)) + decoration (cdr-safe (assq 'text-decoration node)) + pixmap (cdr-safe (assq 'backdrop node)) + index (cdr-safe (assq 'font-size-index node)) + size (or (and index (w3-style-font-size-for-index index)) + (cdr-safe (assq 'font-size node))) + family (cdr-safe (assq 'font-family node)) + weight (cdr-safe (assq 'font-weight node)) + weight (or (cdr-safe (assoc weight + w3-style-font-weight-mappings)) + weight) + style (cdr-safe (assq 'font-style node)) + shorthand (cdr-safe (assq 'font node))) + + (setq voice (if (or voice-person voice-tone) + (intern + (cond + ((and voice-person voice-tone) + (concat voice-person "-" voice-tone)) + (voice-person voice-person) + (voice-tone + (concat "default-voice-" voice-tone)) + (t + (error "IMPOSSIBLE")))))) + + ;; Make sure all 'break' items get intern'd + (if (or style decoration) + (setq style (concat style decoration))) + (setq break-style (assq 'break node)) + (if (and (cdr break-style) (stringp (cdr break-style))) + (setcdr break-style (intern (cdr break-style)))) + (if shorthand + (let ((shorthand (split-string shorthand "[ \t]"))) + (setq size (or (nth 0 shorthand) size) + family (or (nth 1 shorthand) size) + weight (or (nth 2 shorthand) weight) + weight (or (cdr-safe + (assoc weight + w3-style-font-weight-mappings)) + weight) + style (or (nth 3 shorthand) style)))) + (if style + (setq style (mapcar + (function + (lambda (x) + (while (string-match "-" x) + (setq x (concat + (substring x 0 (match-beginning 0)) + (substring x (match-end 0) nil)))) + (intern-soft + (concat "font-set-" (downcase x) "-p")))) + (delete "" (split-string style "[ \t&,]"))))) + (if family (setq family (delete "" (split-string family "[ \t]")))) + (if (or family weight style size) + (progn + (setq font (make-font :family family :weight weight :size size)) + (while style + (and (fboundp (car style)) + (funcall (car style) font t)) + (setq style (cdr style)))) + (setq font nil)) + (if voice (setcdr cur (cons (cons 'voice-spec voice) (cdr cur)))) + (if font (setcdr cur (cons (cons 'font-spec font) (cdr cur)))) + (if fore (setcdr cur (cons (cons 'foreground fore) (cdr cur)))) + (if back (setcdr cur (cons (cons 'background back) (cdr cur)))) + ) + ) + ) + ) + +(defun w3-handle-style (&optional args) + (let ((fname (or (cdr-safe (assq 'href args)) + (cdr-safe (assq 'src args)) + (cdr-safe (assq 'uri args)))) + (type (downcase (or (cdr-safe (assq 'notation args)) + "experimental"))) + (url-working-buffer " *style*") + (base (cdr-safe (assq 'base args))) + (stylesheet nil) + (defines nil) + (cur-sheet w3-current-stylesheet) + (string (cdr-safe (assq 'data args)))) + (if fname (setq fname (url-expand-file-name fname + (cdr-safe + (assoc base w3-base-alist))))) + (save-excursion + (set-buffer (get-buffer-create url-working-buffer)) + (erase-buffer) + (setq url-be-asynchronous nil) + (cond + ((member type '("experimental" "arena" "w3c-style" "css")) + (let ((data (w3-style-parse-css fname string cur-sheet))) + (setq stylesheet (nth 0 data) + defines (nth 1 data)))) + (t + (w3-warn 'html "Unknown stylesheet notation: %s" type)))) + (setq w3-current-stylesheet stylesheet) + (if (and w3-current-stylesheet (fboundp 'make-face)) + (w3-generate-stylesheet-faces w3-current-stylesheet)))) + +(defun w3-display-stylesheet (&optional sheet) + (interactive) + (if (not sheet) (setq sheet w3-current-stylesheet)) + (with-output-to-temp-buffer "W3 Stylesheet" + (set-buffer standard-output) + (emacs-lisp-mode) + (require 'pp) + (pp sheet (current-buffer)))) + +(provide 'w3-style)