1 ;;; Copyright (c) 2006 Zachary Beane, All Rights Reserved
3 ;;; Redistribution and use in source and binary forms, with or without
4 ;;; modification, are permitted provided that the following conditions
7 ;;; * Redistributions of source code must retain the above copyright
8 ;;; notice, this list of conditions and the following disclaimer.
10 ;;; * Redistributions in binary form must reproduce the above
11 ;;; copyright notice, this list of conditions and the following
12 ;;; disclaimer in the documentation and/or other materials
13 ;;; provided with the distribution.
15 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
16 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 ;;; Loading data from the TrueType "name" table.
29 ;;; http://www.microsoft.com/OpenType/OTSpec/name.htm
30 ;;; http://developer.apple.com/fonts/TTRefMan/RM06/Chap6name.html
32 ;;; $Id: name.lisp,v 1.8 2006/02/18 23:13:43 xach Exp $
34 (in-package #:zpb-ttf
)
36 (defvar *name-identifiers
*
58 (defvar *platform-identifiers
*
65 (defvar *unicode-encoding-ids
*
69 :unicode
>=2.0-bmp-only
70 :unicode
>=2.0-full-repertoire
))
72 (defvar *microsoft-encoding-ids
*
85 (defvar *macintosh-encoding-ids
*
120 (defparameter *encoding-tables
*
121 (vector *unicode-encoding-ids
*
122 *macintosh-encoding-ids
*
124 *microsoft-encoding-ids
*
127 (defun encoding-id-name (platform-id encoding-id
)
128 (aref (aref *encoding-tables
* platform-id
) encoding-id
))
130 (defun platform-id-name (platform-id)
131 (aref *platform-identifiers
* platform-id
))
133 (defparameter *macroman-translation-table
*
391 (defconstant +unicode-platform-id
+ 0)
392 (defconstant +macintosh-platform-id
+ 1)
393 (defconstant +iso-platform-id
+ 2)
394 (defconstant +microsoft-platform-id
+ 3)
395 (defconstant +custom-platform-id
+ 4)
397 (defconstant +unicode-2.0-encoding-id
+ 3)
398 (defconstant +microsoft-unicode-bmp-encoding-id
+ 1)
399 (defconstant +microsoft-symbol-encoding-id
+ 0)
400 (defconstant +macintosh-roman-encoding-id
+ 1)
402 ;; Full list of microsoft language IDs is here:
403 ;; http://www.microsoft.com/globaldev/reference/lcid-all.mspx
405 (defconstant +microsoft-us-english-language-id
+ #x0409
)
406 (defconstant +macintosh-english-language-id
+ 1)
407 (defconstant +unicode-language-id
+ 0)
410 (defclass name-entry
()
412 :initarg
:font-loader
413 :accessor font-loader
)
415 :initarg
:platform-id
416 :accessor platform-id
)
418 :initarg
:encoding-id
419 :accessor encoding-id
)
421 :initarg
:language-id
422 :accessor language-id
)
429 :documentation
"The octet offset within the TrueType file stream
430 of the entry's data. *Not* the same as the offset in the NameRecord
431 structure, which is relative to the start of the string data for the
434 :initarg
:entry-length
435 :accessor entry-length
)
438 :writer
(setf value
))
441 :writer
(setf octets
))))
443 (defmethod print-object ((name-entry name-entry
) stream
)
444 (print-unreadable-object (name-entry stream
:type t
)
445 (format stream
"~A (~A/~A/~D)"
446 (aref *name-identifiers
* (name-id name-entry
))
447 (platform-id-name (platform-id name-entry
))
448 (encoding-id-name (platform-id name-entry
)
449 (encoding-id name-entry
))
450 (language-id name-entry
))))
452 (defun unicode-octets-to-string (octets)
453 (let ((string (make-string (/ (length octets
) 2))))
455 (+ (ash (aref octets i
) 16)
456 (aref octets
(1+ i
)))))
457 (loop for i from
0 below
(length octets
) by
2
459 do
(setf (char string j
) (code-char (ref16 i
))))
462 (defun macintosh-octets-to-string (octets)
463 (flet ((macroman->unicode
(point)
464 (code-char (aref *macroman-translation-table
* (1+ (ash point
1))))))
465 (let ((string (make-string (length octets
))))
466 (dotimes (i (length octets
) string
)
467 (setf (schar string i
) (macroman->unicode
(aref octets i
)))))))
469 (defgeneric initialize-name-entry
(name-entry)
470 (:method
(name-entry)
471 (let ((stream (input-stream (font-loader name-entry
)))
472 (octets (make-array (entry-length name-entry
)
473 :element-type
'(unsigned-byte 8)))
475 (platform-id (platform-id name-entry
)))
476 (file-position stream
(offset name-entry
))
477 (read-sequence octets stream
)
478 (cond ((or (= platform-id
+unicode-platform-id
+)
479 (= platform-id
+microsoft-platform-id
+))
480 (setf value
(unicode-octets-to-string octets
)))
481 ((= platform-id
+macintosh-platform-id
+)
482 (setf value
(macintosh-octets-to-string octets
)))
484 (error 'unsupported-value
485 :location
"\"name\" table platform ID"
486 :actual-value platform-id
487 :expected-values
(list +unicode-platform-id
+
488 +microsoft-platform-id
+
489 +macintosh-platform-id
+))))
490 (setf (value name-entry
) value
491 (octets name-entry
) octets
))))
493 (defgeneric value
(name-entry)
494 (:method
(name-entry)
495 (unless (slot-boundp name-entry
'value
)
496 (initialize-name-entry name-entry
))
497 (%value name-entry
)))
499 (defgeneric octets
(name-entry)
500 (:method
(name-entry)
501 (unless (slot-boundp name-entry
'octets
)
502 (initialize-name-entry name-entry
))
503 (%octets name-entry
)))
505 (defun load-name-info (loader)
506 (seek-to-table "name" loader
)
507 (let* ((stream (input-stream loader
))
508 (table-offset (file-position stream
))
509 (format (read-uint16 stream
)))
511 (error 'unsupported-format
512 :location
"\"name\" table"
514 :expected-values
(list 0)))
515 (let* ((count (read-uint16 stream
))
516 (values-offset (read-uint16 stream
))
517 (entries (make-array count
)))
518 (setf (name-entries loader
) entries
)
520 (let ((platform-id (read-uint16 stream
))
521 (encoding-id (read-uint16 stream
))
522 (language-id (read-uint16 stream
))
523 (name-id (read-uint16 stream
))
524 (length (read-uint16 stream
))
525 (offset (read-uint16 stream
)))
526 (setf (aref entries i
)
527 (make-instance 'name-entry
529 :platform-id platform-id
530 :encoding-id encoding-id
531 :language-id language-id
534 :offset
(+ table-offset values-offset offset
))))))))
537 ;;; Fetching info out of the name-entry vector
540 (defun name-identifier-id (symbol)
541 (let ((id (position symbol
*name-identifiers
*)))
544 (error "Unknown NAME identifier: ~S" symbol
))))
547 (defmethod find-name-entry (platform-id encoding-id language-id name-id
548 (font-loader font-loader
))
549 ;; FIXME: this vector is sorted by platform ID, encoding ID,
550 ;; language ID, and name ID, in that order. Could bisect if it
552 (loop for name-entry across
(name-entries font-loader
)
553 when
(and (or (null platform-id
)
554 (= (platform-id name-entry
) platform-id
))
555 (or (null encoding-id
)
556 (= (encoding-id name-entry
) encoding-id
))
557 (or (null language-id
)
558 (= (language-id name-entry
) language-id
))
560 (= (name-id name-entry
) name-id
)))
563 (defmethod name-entry-value (name-designator (font-loader font-loader
))
564 (let* ((name-id (etypecase name-designator
565 (keyword (name-identifier-id name-designator
))
566 (integer name-designator
)))
567 (entry (or (find-name-entry +unicode-platform-id
+
568 +unicode-2.0-encoding-id
+
569 +unicode-language-id
+
572 (find-name-entry +microsoft-platform-id
+
574 +microsoft-us-english-language-id
+
577 (find-name-entry +macintosh-platform-id
+
578 +macintosh-roman-encoding-id
+
579 +macintosh-english-language-id
+
586 (defmethod postscript-name ((font-loader font-loader
))
587 (name-entry-value :postscript-name font-loader
))
589 (defmethod family-name ((font-loader font-loader
))
590 (name-entry-value :font-family font-loader
))
592 (defmethod subfamily-name ((font-loader font-loader
))
593 (name-entry-value :font-subfamily font-loader
))
595 (defmethod full-name ((font-loader font-loader
))
596 (name-entry-value :full-name font-loader
))