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 ;;; https://docs.microsoft.com/en-us/typography/opentype/spec/name
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 (defvar *iso-encoding-ids
*
125 (defparameter *encoding-tables
*
126 (vector *unicode-encoding-ids
*
127 *macintosh-encoding-ids
*
129 *microsoft-encoding-ids
*
132 (defun encoding-id-name (platform-id encoding-id
)
133 (if (and (array-in-bounds-p *encoding-tables
* platform-id
)
134 (aref *encoding-tables
* platform-id
)
135 (array-in-bounds-p (aref *encoding-tables
* platform-id
) encoding-id
))
136 (aref (aref *encoding-tables
* platform-id
) encoding-id
)
139 (defun platform-id-name (platform-id)
140 (if (array-in-bounds-p *platform-identifiers
* platform-id
)
141 (aref *platform-identifiers
* platform-id
)
144 (defparameter *macroman-translation-table
*
402 (defconstant +unicode-platform-id
+ 0)
403 (defconstant +macintosh-platform-id
+ 1)
404 (defconstant +iso-platform-id
+ 2)
405 (defconstant +microsoft-platform-id
+ 3)
406 (defconstant +custom-platform-id
+ 4)
408 (defconstant +unicode-2.0-encoding-id
+ 3)
409 (defconstant +unicode-2.0-full-encoding-id
+ 4)
410 (defconstant +microsoft-unicode-bmp-encoding-id
+ 1)
411 (defconstant +microsoft-unicode-ucs4-encoding-id
+ 10)
412 (defconstant +microsoft-symbol-encoding-id
+ 0)
413 (defconstant +macintosh-roman-encoding-id
+ 1)
415 ;; Full list of microsoft language IDs is here:
416 ;; http://www.microsoft.com/globaldev/reference/lcid-all.mspx
418 (defconstant +microsoft-us-english-language-id
+ #x0409
)
419 (defconstant +macintosh-english-language-id
+ 1)
420 (defconstant +unicode-language-id
+ 0)
423 (defclass name-entry
()
425 :initarg
:font-loader
426 :accessor font-loader
)
428 :initarg
:platform-id
429 :accessor platform-id
)
431 :initarg
:encoding-id
432 :accessor encoding-id
)
434 :initarg
:language-id
435 :accessor language-id
)
442 :documentation
"The octet offset within the TrueType file stream
443 of the entry's data. *Not* the same as the offset in the NameRecord
444 structure, which is relative to the start of the string data for the
447 :initarg
:entry-length
448 :accessor entry-length
)
451 :writer
(setf value
))
454 :writer
(setf octets
))))
456 (defmethod print-object ((name-entry name-entry
) stream
)
457 (print-unreadable-object (name-entry stream
:type t
)
458 (format stream
"~A (~A/~A/~D)"
459 (aref *name-identifiers
* (name-id name-entry
))
460 (platform-id-name (platform-id name-entry
))
461 (encoding-id-name (platform-id name-entry
)
462 (encoding-id name-entry
))
463 (language-id name-entry
))))
465 (defun unicode-octets-to-string (octets)
466 (let ((string (make-string (/ (length octets
) 2))))
468 (+ (ash (aref octets i
) 16)
469 (aref octets
(1+ i
)))))
470 (loop for i from
0 below
(length octets
) by
2
472 do
(setf (char string j
) (code-char (ref16 i
))))
475 (defun macintosh-octets-to-string (octets)
476 (flet ((macroman->unicode
(point)
477 (code-char (aref *macroman-translation-table
* (1+ (ash point
1))))))
478 (let ((string (make-string (length octets
))))
479 (dotimes (i (length octets
) string
)
480 (setf (schar string i
) (macroman->unicode
(aref octets i
)))))))
482 (defgeneric initialize-name-entry
(name-entry)
483 (:method
(name-entry)
484 (let ((stream (input-stream (font-loader name-entry
)))
485 (octets (make-array (entry-length name-entry
)
486 :element-type
'(unsigned-byte 8)))
488 (platform-id (platform-id name-entry
)))
489 (file-position stream
(offset name-entry
))
490 (read-sequence octets stream
)
491 (cond ((or (= platform-id
+unicode-platform-id
+)
492 (= platform-id
+microsoft-platform-id
+))
493 (setf value
(unicode-octets-to-string octets
)))
494 ((= platform-id
+macintosh-platform-id
+)
495 (setf value
(macintosh-octets-to-string octets
)))
497 (error 'unsupported-value
498 :location
"\"name\" table platform ID"
499 :actual-value platform-id
500 :expected-values
(list +unicode-platform-id
+
501 +microsoft-platform-id
+
502 +macintosh-platform-id
+))))
503 (setf (value name-entry
) value
504 (octets name-entry
) octets
))))
506 (defgeneric value
(name-entry)
507 (:method
(name-entry)
508 (unless (slot-boundp name-entry
'value
)
509 (initialize-name-entry name-entry
))
510 (%value name-entry
)))
512 (defgeneric octets
(name-entry)
513 (:method
(name-entry)
514 (unless (slot-boundp name-entry
'octets
)
515 (initialize-name-entry name-entry
))
516 (%octets name-entry
)))
518 (defun load-name-info (loader)
519 (seek-to-table "name" loader
)
520 (let* ((stream (input-stream loader
))
521 (table-offset (file-position stream
))
522 (format (read-uint16 stream
)))
524 (error 'unsupported-format
525 :location
"\"name\" table"
527 :expected-values
(list 0)))
528 (let* ((count (read-uint16 stream
))
529 (values-offset (read-uint16 stream
))
530 (entries (make-array count
)))
531 (setf (name-entries loader
) entries
)
533 (let ((platform-id (read-uint16 stream
))
534 (encoding-id (read-uint16 stream
))
535 (language-id (read-uint16 stream
))
536 (name-id (read-uint16 stream
))
537 (length (read-uint16 stream
))
538 (offset (read-uint16 stream
)))
539 (setf (aref entries i
)
540 (make-instance 'name-entry
542 :platform-id platform-id
543 :encoding-id encoding-id
544 :language-id language-id
547 :offset
(+ table-offset values-offset offset
))))))))
550 ;;; Fetching info out of the name-entry vector
553 (defun name-identifier-id (symbol)
554 (let ((id (position symbol
*name-identifiers
*)))
557 (error "Unknown NAME identifier: ~S" symbol
))))
560 (defmethod find-name-entry (platform-id encoding-id language-id name-id
561 (font-loader font-loader
))
562 ;; FIXME: this vector is sorted by platform ID, encoding ID,
563 ;; language ID, and name ID, in that order. Could bisect if it
565 (loop for name-entry across
(name-entries font-loader
)
566 when
(and (or (null platform-id
)
567 (= (platform-id name-entry
) platform-id
))
568 (or (null encoding-id
)
569 (= (encoding-id name-entry
) encoding-id
))
570 (or (null language-id
)
571 (= (language-id name-entry
) language-id
))
573 (= (name-id name-entry
) name-id
)))
576 (defmethod name-entry-value (name-designator (font-loader font-loader
))
577 (let* ((name-id (etypecase name-designator
578 (keyword (name-identifier-id name-designator
))
579 (integer name-designator
)))
580 (entry (or (find-name-entry +unicode-platform-id
+
581 +unicode-2.0-encoding-id
+
582 +unicode-language-id
+
585 (find-name-entry +microsoft-platform-id
+
587 +microsoft-us-english-language-id
+
590 (find-name-entry +macintosh-platform-id
+
591 +macintosh-roman-encoding-id
+
592 +macintosh-english-language-id
+
599 (defmethod postscript-name ((font-loader font-loader
))
600 (name-entry-value :postscript-name font-loader
))
602 (defmethod family-name ((font-loader font-loader
))
603 (name-entry-value :font-family font-loader
))
605 (defmethod subfamily-name ((font-loader font-loader
))
606 (name-entry-value :font-subfamily font-loader
))
608 (defmethod full-name ((font-loader font-loader
))
609 (name-entry-value :full-name font-loader
))