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 ;;; Interface functions for creating, initializing, and closing a
28 ;;; FONT-LOADER object.
30 ;;; $Id: font-loader-interface.lisp,v 1.6 2006/03/23 22:20:35 xach Exp $
32 (in-package #:zpb-ttf
)
34 (defun arrange-finalization (object stream
)
35 (flet ((quietly-close (&optional object
)
36 (declare (ignore object
))
37 (ignore-errors (close stream
))))
39 (sb-ext:finalize object
#'quietly-close
)
41 (ext:finalize object
#'quietly-close
)
43 (ext:finalize object
#'quietly-close
)
45 (excl:schedule-finalization object
#'quietly-close
)))
48 (defun check-magic (magic &rest ok
)
52 ((= magic
(tag->number
"typ1"))
53 (error 'unsupported-format
54 :location
"font header"
55 :description
"Old style of PostScript font housed in a sfnt wrapper not supported."
58 ((= magic
(tag->number
"OTTO"))
59 (error 'unsupported-format
60 :location
"font header"
61 :description
"OpenType font with PostScript outlines not supported."
66 :location
"font header"
68 :actual-value magic
))))
70 ;;; FIXME: move most/all of this stuff into initialize-instance
73 (defun open-font-loader-from-stream (input-stream &key
(collection-index 0))
74 (let ((magic (read-uint32 input-stream
))
76 (check-magic magic
#x00010000
79 (when (= magic
(tag->number
"ttcf"))
80 (let ((version (read-uint32 input-stream
)))
81 (check-version "ttc header" version
#x00010000
#x00020000
)
82 (setf font-count
(read-uint32 input-stream
))
83 (let* ((offset-table (make-array font-count
))
85 (when (> collection-index font-count
)
86 (error 'unsupported-value
87 :description
"Font index out of range"
88 :actual-value collection-index
89 :expected-values
(list font-count
)))
90 (loop for i below font-count
91 do
(setf (aref offset-table i
) (read-uint32 input-stream
)))
92 (when (= version
#x00020000
)
93 (let ((flag (read-uint32 input-stream
))
94 (length (read-uint32 input-stream
))
95 (offset (read-uint32 input-stream
)))
96 (list flag length offset
)
97 (when (= #x44534947 flag
)
98 (setf dsig
(list length offset
)))))
99 ;; seek to font offset table
100 (file-position input-stream
(aref offset-table collection-index
))
101 (let ((magic2 (read-uint32 input-stream
)))
102 (check-magic magic2
#x00010000
(tag->number
"true"))))))
104 (let* ((table-count (read-uint16 input-stream
))
105 (font-loader (make-instance 'font-loader
106 :input-stream input-stream
107 :table-count table-count
108 :collection-font-cont font-count
109 :collection-font-index
112 ;; skip the unused stuff:
113 ;; searchRange, entrySelector, rangeShift
114 (read-uint16 input-stream
)
115 (read-uint16 input-stream
)
116 (read-uint16 input-stream
)
117 (loop repeat table-count
118 for tag
= (read-uint32 input-stream
)
119 for checksum
= (read-uint32 input-stream
)
120 for offset
= (read-uint32 input-stream
)
121 for size
= (read-uint32 input-stream
)
122 do
(setf (gethash tag
(tables font-loader
))
123 (make-instance 'table-info
125 :name
(number->tag tag
)
127 (load-maxp-info font-loader
)
128 (load-head-info font-loader
)
129 (load-kern-info font-loader
)
130 (load-loca-info font-loader
)
131 (load-name-info font-loader
)
132 (load-cmap-info font-loader
)
133 (load-post-info font-loader
)
134 (load-hhea-info font-loader
)
135 (load-hmtx-info font-loader
)
136 (load-vhea-info font-loader
)
137 (load-vmtx-info font-loader
)
138 (setf (glyph-cache font-loader
)
139 (make-array (glyph-count font-loader
) :initial-element nil
))
142 (defun open-font-loader-from-file (thing &key
(collection-index 0))
143 (let ((stream (open thing
145 :element-type
'(unsigned-byte 8)
146 #+ccl
:sharing
#+ccl
:external
)))
147 (let ((font-loader (open-font-loader-from-stream
148 stream
:collection-index collection-index
)))
149 (arrange-finalization font-loader stream
)
152 (defun open-font-loader (thing &key
(collection-index 0))
156 ;; We either don't have a collection, or want same font from
158 ((or (not (collection-font-index thing
))
159 (= collection-index
(collection-font-index thing
)))
160 (unless (open-stream-p (input-stream thing
))
161 (setf (input-stream thing
) (open (input-stream thing
))))
164 (open-font-loader-from-file (input-stream thing
)
165 :collection-index collection-index
))))
167 (if (open-stream-p thing
)
168 (open-font-loader-from-stream thing
:collection-index collection-index
)
169 (error "~A is not an open stream" thing
)))
171 (open-font-loader-from-file thing
:collection-index collection-index
))))
173 (defun close-font-loader (loader)
174 (close (input-stream loader
)))
176 (defmacro with-font-loader
((loader file
&key
(collection-index 0)) &body body
)
180 (setf ,loader
(open-font-loader ,file
181 :collection-index
,collection-index
))
184 (close-font-loader ,loader
)))))