Fix up comment convention on the arch-tag lines.
[bpt/emacs.git] / lisp / ps-bdf.el
CommitLineData
e8af40ee 1;;; ps-bdf.el --- BDF font file handler for ps-print
e62e3e6b 2
409cc4a3 3;; Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
38087490 4;; Free Software Foundation, Inc.
409cc4a3
GM
5;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
6;; 2008
ce03bf76
KH
7;; National Institute of Advanced Industrial Science and Technology (AIST)
8;; Registration Number H14PRO021
e62e3e6b 9
76875dcb
KH
10;; Copyright (C) 2003
11;; National Institute of Advanced Industrial Science and Technology (AIST)
12;; Registration Number H13PRO009
e62e3e6b 13
3ad114e5 14;; Keywords: wp, BDF, font, PostScript
76875dcb 15;; Maintainer: Kenichi Handa <handa@m17n.org>
e62e3e6b
KH
16
17;; This file is part of GNU Emacs.
18
19;; GNU Emacs is free software; you can redistribute it and/or modify
20;; it under the terms of the GNU General Public License as published by
a32f6e9e 21;; the Free Software Foundation; either version 3, or (at your option)
e62e3e6b
KH
22;; any later version.
23
24;; GNU Emacs is distributed in the hope that it will be useful,
25;; but WITHOUT ANY WARRANTY; without even the implied warranty of
26;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27;; GNU General Public License for more details.
28
29;; You should have received a copy of the GNU General Public License
30;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
31;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
32;; Boston, MA 02110-1301, USA.
e62e3e6b
KH
33
34;;; Commentary:
35
36;; Functions for getting bitmap information from X's BDF font file are
37;; provided.
38
39;;; Code:
40
64d8e7fd 41(eval-and-compile
c97a3f22 42 (require 'ps-mule))
e62e3e6b
KH
43
44;;;###autoload
3e3cf0a7 45(defvar bdf-directory-list
7a1e1973 46 (if (memq system-type '(ms-dos windows-nt))
0a51cf3d 47 (list (expand-file-name "fonts/bdf" installation-directory))
3e3cf0a7 48 '("/usr/local/share/emacs/fonts/bdf"))
1b3172da 49 "*List of directories to search for `BDF' font files.
5062e90d 50The default value is '(\"/usr/local/share/emacs/fonts/bdf\").")
e62e3e6b 51
3f4f2289
EZ
52;; MS-DOS and MS-Windows users like to move the binary around after
53;; it's built, but the value above is computed at load-up time.
7a1e1973 54(and (memq system-type '(ms-dos windows-nt))
0a51cf3d
EZ
55 (setq bdf-directory-list
56 (list (expand-file-name "fonts/bdf" installation-directory))))
57
e62e3e6b 58(defun bdf-expand-file-name (bdfname)
64d8e7fd 59 "Return an absolute path name of a `BDF' font file BDFNAME.
e62e3e6b
KH
60It searches directories listed in the variable `bdf-directory-list'
61for BDFNAME."
62 (if (file-name-absolute-p bdfname)
63 (and (file-readable-p bdfname)
64 bdfname)
76875dcb
KH
65 (catch 'tag
66 (dolist (dir bdf-directory-list)
67 (let ((absolute-path (expand-file-name bdfname dir)))
68 (if (file-readable-p absolute-path)
69 (throw 'tag absolute-path)))))))
e62e3e6b
KH
70
71(defsubst bdf-file-mod-time (filename)
72 "Return modification time of FILENAME.
73The value is a list of two integers, the first integer has high-order
7416 bits, the second has low 16 bits."
75 (nth 5 (file-attributes filename)))
76
77(defun bdf-file-newer-than-time (filename mod-time)
78 "Return non-nil if and only if FILENAME is newer than MOD-TIME.
79MOD-TIME is a modification time as a list of two integers, the first
80integer has high-order 16 bits, the second has low 16 bits."
76875dcb
KH
81 (let* ((new-mod-time (bdf-file-mod-time filename))
82 (new-time (car new-mod-time))
83 (time (car mod-time)))
84 (or (> new-time time)
85 (and (= new-time time)
86 (> (nth 1 new-mod-time) (nth 1 mod-time))))))
e62e3e6b
KH
87
88(defun bdf-find-file (bdfname)
89 "Return a buffer visiting a bdf file BDFNAME.
76875dcb 90BDFNAME must be an absolute file name.
e62e3e6b 91If BDFNAME doesn't exist, return nil."
76875dcb
KH
92 (and (file-readable-p bdfname)
93 (let ((buf (generate-new-buffer " *bdf-work*"))
94 (coding-system-for-read 'no-conversion))
95 (save-excursion
96 (set-buffer buf)
97 (insert-file-contents bdfname)
98 buf))))
e62e3e6b 99
a5f01960
EZ
100(defvar bdf-cache-file (if (eq system-type 'ms-dos)
101 ;; convert-standard-filename doesn't
102 ;; guarantee that the .el extension will be
103 ;; preserved.
104 "~/_bdfcache.el"
105 (convert-standard-filename "~/.bdfcache.el"))
e62e3e6b
KH
106 "Name of cache file which contains information of `BDF' font files.")
107
108(defvar bdf-cache nil
109 "Cached information of `BDF' font files. It is a list of FONT-INFO.
110FONT-INFO is a list of the following format:
76875dcb 111 (ABSOLUTE-FILE-NAME MOD-TIME SIZE FONT-BOUNDING-BOX
e62e3e6b
KH
112 RELATIVE-COMPOSE BASELINE-OFFSET CODE-RANGE MAXLEN OFFSET-VECTOR)
113See the documentation of the function `bdf-read-font-info' for more detail.")
114
115(defun bdf-read-cache ()
116 "Return a cached information about `BDF' font files from a cache file.
117The variable `bdf-cache-file' holds the cache file name.
118If the cache file is not readable, this return nil."
119 (setq bdf-cache nil)
120 (condition-case nil
121 (and (file-readable-p bdf-cache-file)
122 (progn
123 (load-file bdf-cache-file)
124 (if (listp bdf-cache)
125 bdf-cache
126 (setq bdf-cache nil))))
127 (error nil)))
128
129(defun bdf-write-cache ()
130 "Write out cached information of `BDF' font file to a file.
131The variable `bdf-cache-file' holds the cache file name.
64d8e7fd 132The file is written if and only if the file already exists and writable."
e62e3e6b
KH
133 (and bdf-cache
134 (file-exists-p bdf-cache-file)
135 (file-writable-p bdf-cache-file)
136 (write-region (format "(setq bdf-cache '%S)\n" bdf-cache)
137 nil bdf-cache-file)))
138
139(defun bdf-set-cache (font-info)
140 "Cache FONT-INFO as information about one `BDF' font file.
141FONT-INFO is a list of the following format:
76875dcb 142 (ABSOLUTE-FILE-NAME MOD-TIME SIZE FONT-BOUNDING-BOX
e62e3e6b
KH
143 RELATIVE-COMPOSE BASELINE-OFFSET CODE-RANGE MAXLEN OFFSET-VECTOR)
144See the documentation of the function `bdf-read-font-info' for more detail."
145 (let ((slot (assoc (car font-info) bdf-cache)))
146 (if slot
147 (setcdr slot (cdr font-info))
148 (setq bdf-cache (cons font-info bdf-cache)))))
149
150(defun bdf-initialize ()
151 "Initialize `bdf' library."
152 (and (bdf-read-cache)
153 (add-hook 'kill-emacs-hook 'bdf-write-cache)))
154
155(defun bdf-compact-code (code code-range)
156 (if (or (< code (aref code-range 4))
157 (> code (aref code-range 5)))
158 (setq code (aref code-range 6)))
159 (+ (* (- (lsh code -8) (aref code-range 0))
160 (1+ (- (aref code-range 3) (aref code-range 2))))
161 (- (logand code 255) (aref code-range 2))))
162
163(defun bdf-expand-code (code code-range)
164 (let ((code0-range (1+ (- (aref code-range 3) (aref code-range 2)))))
165 (+ (* (+ (/ code code0-range) (aref code-range 0)) 256)
166 (+ (% code code0-range) (aref code-range 2)))))
167
168(defun bdf-search-and-read (match limit)
169 (goto-char (point-min))
170 (and (search-forward match limit t)
171 (progn
172 (goto-char (match-end 0))
173 (read (current-buffer)))))
174
175(defun bdf-read-font-info (bdfname)
176 "Read `BDF' font file BDFNAME and return information (FONT-INFO) of the file.
76875dcb 177BDFNAME must be an absolute file name.
e62e3e6b 178FONT-INFO is a list of the following format:
76875dcb 179 (BDFFILE MOD-TIME FONT-BOUNDING-BOX
e62e3e6b
KH
180 RELATIVE-COMPOSE BASELINE-OFFSET CODE-RANGE MAXLEN OFFSET-VECTOR)
181
e62e3e6b
KH
182MOD-TIME is last modification time as a list of two integers, the
183first integer has high-order 16 bits, the second has low 16 bits.
184
76875dcb
KH
185SIZE is a size of the font on 72 dpi device. This value is got
186from SIZE record of the font.
e62e3e6b
KH
187
188FONT-BOUNDING-BOX is the font bounding box as a list of four integers,
189BBX-WIDTH, BBX-HEIGHT, BBX-XOFF, and BBX-YOFF.
190
191RELATIVE-COMPOSE is an integer value of the font's property
192`_MULE_RELATIVE_COMPOSE'. If the font doesn't have this property, the
193value is 0.
194
195BASELINE-OFFSET is an integer value of the font's property
196`_MULE_BASELINE_OFFSET'. If the font doesn't have this property, the
197value is 0.
198
199CODE-RANGE is a vector of minimum 1st byte, maximum 1st byte, minimum
2002nd byte, maximum 2nd byte, minimum code, maximum code, and default
201code. For 1-byte fonts, the first two elements are 0.
202
64d8e7fd 203MAXLEN is a maximum bytes of one glyph information in the font file.
e62e3e6b
KH
204
205OFFSET-VECTOR is a vector of a file position which starts bitmap data
206of the glyph in the font file.
207
208Nth element of OFFSET-VECTOR is a file position for the glyph of code
209CODE, where N and CODE are in the following relation:
210 (bdf-compact-code CODE) => N, (bdf-expand-code N) => CODE"
76875dcb 211 (let* ((buf (bdf-find-file bdfname))
e62e3e6b
KH
212 (maxlen 0)
213 (relative-compose 'false)
214 (baseline-offset 0)
215 size
76875dcb 216 dpi
f1180544 217 font-bounding-box
e62e3e6b
KH
218 default-char
219 code-range
220 offset-vector)
221 (if buf
222 (message "Reading %s..." bdfname)
223 (error "BDF file %s doesn't exist" bdfname))
224 (unwind-protect
225 (save-excursion
226 (set-buffer buf)
227 (goto-char (point-min))
228 (search-forward "\nFONTBOUNDINGBOX")
229 (setq font-bounding-box
230 (vector (read (current-buffer)) (read (current-buffer))
231 (read (current-buffer)) (read (current-buffer))))
232 ;; The following kludgy code is to avoid bugs of fonts
233 ;; jiskan16.bdf and jiskan24.bdf distributed with X.
234 ;; They contain wrong FONTBOUNDINGBOX.
235 (and (> (aref font-bounding-box 3) 0)
236 (string-match "jiskan\\(16\\|24\\)" bdfname)
237 (aset font-bounding-box 3
238 (- (aref font-bounding-box 3))))
239
240 (goto-char (point-min))
76875dcb
KH
241 (search-forward "\nFONT ")
242 (if (looking-at "-[^-]*-[^-]*-[^-]*-[^-]*-[^-]*-[^-]*-\\([0-9]+\\)")
4836694e 243 (setq size (string-to-number (match-string 1)))
76875dcb
KH
244 (search-forward "\nSIZE ")
245 (setq size (read (current-buffer)))
20525d8c 246 ;; The following kludgy code is to avoid bugs of several
76875dcb
KH
247 ;; fonts which have wrong SIZE record.
248 (and (string-match "jiskan" bdfname)
249 (<= size (/ (aref font-bounding-box 1) 3))
250 (setq size (aref font-bounding-box 1)))
251 (setq dpi (read (current-buffer)))
252 (if (and (> dpi 0) (/= dpi 72))
253 (setq size (/ (* size dpi) 72))))
e62e3e6b
KH
254
255 (setq default-char (bdf-search-and-read "\nDEFAULT_CHAR" nil))
256
257 (search-forward "\nSTARTCHAR")
258 (forward-line -1)
259 (let ((limit (point)))
260 (setq relative-compose
261 (or (bdf-search-and-read "\n_MULE_RELATIVE_COMPOSE" limit)
262 'false)
263 baseline-offset
264 (or (bdf-search-and-read "\n_MULE_BASELINE_OFFSET" limit)
265 0)))
266
267 (let ((min-code0 256) (min-code1 256) (min-code 65536)
268 (max-code0 0) (max-code1 0) (max-code 0)
64d8e7fd 269 glyph glyph-list code0 code1 code offset)
e62e3e6b
KH
270
271 (while (search-forward "\nSTARTCHAR" nil t)
272 (setq offset (line-beginning-position))
273 (search-forward "\nENCODING")
3509543c
KH
274 (setq code (read (current-buffer)))
275 (if (< code 0)
276 (search-forward "ENDCHAR")
277 (setq code0 (lsh code -8)
278 code1 (logand code 255)
279 min-code (min min-code code)
280 max-code (max max-code code)
281 min-code0 (min min-code0 code0)
282 max-code0 (max max-code0 code0)
283 min-code1 (min min-code1 code1)
284 max-code1 (max max-code1 code1))
285 (search-forward "ENDCHAR")
286 (setq maxlen (max maxlen (- (point) offset))
287 glyph-list (cons (cons code offset) glyph-list))))
e62e3e6b
KH
288
289 (setq code-range
290 (vector min-code0 max-code0 min-code1 max-code1
291 min-code max-code (or default-char min-code))
292 offset-vector
293 (make-vector (1+ (bdf-compact-code max-code code-range))
294 nil))
295
296 (while glyph-list
297 (setq glyph (car glyph-list)
298 glyph-list (cdr glyph-list))
299 (aset offset-vector
300 (bdf-compact-code (car glyph) code-range)
301 (cdr glyph)))))
302
303 (kill-buffer buf))
304 (message "Reading %s...done" bdfname)
76875dcb 305 (list bdfname (bdf-file-mod-time bdfname)
e62e3e6b
KH
306 size font-bounding-box relative-compose baseline-offset
307 code-range maxlen offset-vector)))
308
76875dcb
KH
309(defsubst bdf-info-absolute-path (font-info) (nth 0 font-info))
310(defsubst bdf-info-mod-time (font-info) (nth 1 font-info))
311(defsubst bdf-info-size (font-info) (nth 2 font-info))
312(defsubst bdf-info-font-bounding-box (font-info) (nth 3 font-info))
313(defsubst bdf-info-relative-compose (font-info) (nth 4 font-info))
314(defsubst bdf-info-baseline-offset (font-info) (nth 5 font-info))
315(defsubst bdf-info-code-range (font-info) (nth 6 font-info))
316(defsubst bdf-info-maxlen (font-info) (nth 7 font-info))
317(defsubst bdf-info-offset-vector (font-info) (nth 8 font-info))
e62e3e6b
KH
318
319(defun bdf-get-font-info (bdfname)
320 "Return information about `BDF' font file BDFNAME.
76875dcb 321BDFNAME must be an absolute file name.
e62e3e6b 322The value FONT-INFO is a list of the following format:
76875dcb 323 (BDFNAME MOD-TIME SIZE FONT-BOUNDING-BOX
e62e3e6b
KH
324 RELATIVE-COMPOSE BASELINE-OFFSET CODE-RANGE MAXLEN OFFSET-VECTOR)
325See the documentation of the function `bdf-read-font-info' for more detail."
326 (or bdf-cache
327 (bdf-read-cache))
328 (let ((font-info (assoc bdfname bdf-cache)))
329 (if (or (not font-info)
76875dcb 330 (not (file-readable-p bdfname))
e62e3e6b
KH
331 (bdf-file-newer-than-time bdfname (bdf-info-mod-time font-info)))
332 (progn
333 (setq font-info (bdf-read-font-info bdfname))
334 (bdf-set-cache font-info)))
335 font-info))
336
76875dcb 337(defun bdf-read-bitmap (bdfname offset maxlen relative-compose)
64d8e7fd
GM
338 "Read `BDF' font file BDFNAME to get bitmap data at file position OFFSET.
339BDFNAME is an absolute path name of the font file.
e62e3e6b
KH
340MAXLEN specifies how many bytes we should read at least.
341The value is a list of DWIDTH, BBX, and BITMAP-STRING.
342DWIDTH is a pixel width of a glyph.
343BBX is a bounding box of the glyph.
344BITMAP-STRING is a string representing bits by hexadecimal digits."
0240cfba 345 (let* ((coding-system-for-read 'no-conversion)
76875dcb 346 (bbx (bdf-info-font-bounding-box (bdf-get-font-info bdfname)))
0240cfba
GM
347 (dwidth (elt bbx 0))
348 (bitmap-string "")
349 height yoff)
e62e3e6b
KH
350 (condition-case nil
351 (with-temp-buffer
352 (insert-file-contents bdfname nil offset (+ offset maxlen))
353 (goto-char (point-min))
354 (search-forward "\nDWIDTH")
355 (setq dwidth (read (current-buffer)))
76875dcb
KH
356 (if (= dwidth 0)
357 (setq dwidth 0.1))
e62e3e6b
KH
358 (goto-char (point-min))
359 (search-forward "\nBBX")
360 (setq bbx (vector (read (current-buffer)) (read (current-buffer))
361 (read (current-buffer)) (read (current-buffer)))
64d8e7fd
GM
362 height (aref bbx 1)
363 yoff (aref bbx 3))
e62e3e6b
KH
364 (search-forward "\nBITMAP")
365 (forward-line 1)
366 (delete-region (point-min) (point))
367 (and (looking-at "\\(0+\n\\)+")
368 (progn
369 (setq height (- height (count-lines (point) (match-end 0))))
370 (delete-region (point) (match-end 0))))
371 (or (looking-at "ENDCHAR")
372 (progn
373 (search-forward "ENDCHAR" nil 'move)
374 (forward-line -1)
375 (while (looking-at "0+$")
376 (setq yoff (1+ yoff)
377 height (1- height))
378 (forward-line -1))
379 (forward-line 1)))
380 (aset bbx 1 height)
381 (aset bbx 3 yoff)
382 (delete-region (point) (point-max))
383 (goto-char (point-min))
384 (while (not (eobp))
385 (end-of-line)
386 (delete-char 1))
387 (setq bitmap-string (buffer-string)))
388 (error nil))
76875dcb
KH
389 (vector dwidth (aref bbx 0) (aref bbx 1) (aref bbx 2) (aref bbx 3)
390 (concat "<" bitmap-string ">")
391 (or relative-compose 'false))))
392
393(defun bdf-get-bitmap (bdfname code)
394 "Return bitmap information of glyph of CODE in `BDF' font file BDFNAME.
395CODE is an encoding number of glyph in the file.
396The value is a list (DWIDTH BBX BITMAP-STRING).
e62e3e6b
KH
397DWIDTH is a pixel width of a glyph.
398BBX is a bounding box of the glyph.
399BITMAP-STRING is a string representing bits by hexadecimal digits."
76875dcb
KH
400 (let* ((info (bdf-get-font-info bdfname))
401 (maxlen (bdf-info-maxlen info))
402 (code-range (bdf-info-code-range info))
403 (offset-vector (bdf-info-offset-vector info)))
404 (bdf-read-bitmap bdfname
405 (aref offset-vector (bdf-compact-code code code-range))
406 maxlen (bdf-info-relative-compose info))))
407
408;;; Interface to ps-mule.el
e62e3e6b
KH
409
410;; Called from ps-mule-init-external-library.
411(defun bdf-generate-prologue ()
412 (or bdf-cache
413 (bdf-initialize))
414 (ps-mule-generate-bitmap-prologue))
415
76875dcb
KH
416;; Called from ps-mule-check-font.
417(defun bdf-check-font (font-spec)
418 (let ((font-name-list (ps-mule-font-spec-name font-spec)))
419 (ps-mule-font-spec-set-name
420 font-spec
421 (if (stringp font-name-list)
422 (bdf-expand-file-name font-name-list)
423 (catch 'tag
424 (dolist (font-name font-name-list)
425 (setq font-name (bdf-expand-file-name font-name))
426 (if font-name
427 (throw 'tag font-name))))))))
428
e62e3e6b 429;; Called from ps-mule-generate-font.
76875dcb
KH
430(defun bdf-generate-font (font-spec)
431 (let ((info (bdf-get-font-info (ps-mule-font-spec-name font-spec))))
432 (ps-mule-font-spec-set-extra
433 font-spec (bdf-info-absolute-path info))
434 (ps-mule-generate-bitmap-font font-spec
435 (bdf-info-size info)
436 (bdf-info-relative-compose info)
437 (bdf-info-baseline-offset info)
438 (bdf-info-font-bounding-box info))))
439
440;; Called from ps-mule-generate-glyph.
441(defun bdf-generate-glyph (font-spec char)
442 (let ((font-name (ps-mule-font-spec-extra font-spec))
443 (code (ps-mule-encode-char char font-spec)))
444 (ps-mule-generate-bitmap-glyph font-spec char code
445 (bdf-get-bitmap font-name code))))
e62e3e6b
KH
446
447(provide 'ps-bdf)
448
cbee283d 449;; arch-tag: 9b875ba8-565a-4ecf-acaa-30cee732c898
e62e3e6b 450;;; ps-bdf.el ends here