;;; cl-pdf copyright 2002-2003 Marc Battyani see license.txt for the details
;;; You can reach me at marc.battyani@fractalconcept.com or marc@battyani.net
;;; The homepage of cl-pdf is here: http://www.fractalconcept.com/asp/html/cl-pdf.html

(in-package pdf)

(defconstant +pfb-marker+ 128)
(defconstant +pfb-ascii+ 1)
(defconstant +pfb-binary+ 2)
(defconstant +pfb-done+ 3)

(defclass t1-font-metrics (font-metrics)
  ((binary-data :accessor binary-data :initform nil)
   (length1 :accessor length1)
   (length2 :accessor length2)
   (length3 :accessor length3)))

(defun read-pfb-length (data start)
  (let ((length (aref data start)))
    (setf (ldb (byte 8 8) length) (aref data (1+ start)))
    (setf (ldb (byte 8 16) length) (aref data (+ start 2)))
    (setf (ldb (byte 8 24) length) (aref data (+ start 3)))
    length))

(defun read-pfb-seg-size (data start marker)
  (assert (and (= (aref data start) +pfb-marker+)(= (aref data (1+ start)) marker)))
  (values (+ start 6) (read-pfb-length data (+ start 2))))

(defun read-pfb-file (pathname t1fm)
  (let (data length start1 length1 start2 length2 start3 length3 binary-data)
    (with-open-file (s pathname :direction :input :element-type '(unsigned-byte 8))
      (setf length (file-length s))
      (setf data (make-array length :element-type '(unsigned-byte 8)))
      (read-sequence data s))
    (setf (values start1 length1) (read-pfb-seg-size data 0 +pfb-ascii+))
    (setf (values start2 length2) (read-pfb-seg-size data (+ start1 length1) +pfb-binary+))
    (setf (values start3 length3) (read-pfb-seg-size data (+ start2 length2) +pfb-ascii+))
    (assert (<= (+ start3 length3) length))
    (setf binary-data (make-array (+ length1 length2 length3) :element-type '(unsigned-byte 8)))
    (setf (subseq binary-data 0 length1)(subseq data start1 (+ start1 length1)))
    (setf (subseq binary-data length1 (+ length1 length2))
	  (subseq data start2 (+ start2 length2)))
    (setf (subseq binary-data (+ length1 length2)(+ length1 length2 length3))
	  (subseq data start3 (+ start3 length3)))
    (setf (binary-data t1fm) binary-data
	  (length1 t1fm) length1
	  (length2 t1fm) length2
	  (length3 t1fm) length3)))

(defun load-t1-font (afm-file  &optional pfb-file)
  (let ((t1fm (read-afm-file afm-file 't1-font-metrics)))
    (when pfb-file
      (read-pfb-file pfb-file t1fm))
    t1fm))

(defmethod font-descriptor ((t1fm t1-font-metrics)
                            &key (embed *embed-fonts*) (errorp t))
  (flet ((conv-dim (d) (round (* 1000 d))))
    (make-instance 'indirect-object :content
      (make-instance 'dictionary  ;:obj-number 0 :no-link t
        :dict-values        
	`(("/Type" . "/FontDescriptor")
	  ("/FontName"  . ,(add-/ (font-name t1fm)))
	  ;; 4=Symbolic - contains characters outside the standard Latin character set.
	  ("/Flags" . 4)
	  ("/FontBBox" . ,(map 'vector #'conv-dim (font-bbox t1fm)))
	  ("/ItalicAngle" . ,(conv-dim (italic-angle t1fm)))
	  ("/Ascent" . ,(conv-dim (ascender t1fm)))
	  ("/Descent" . ,(conv-dim (descender t1fm)))
	  ("/CapHeight" . ,(conv-dim (cap-height t1fm)))
	  ("/XHeight" . ,(conv-dim (x-height t1fm)))
	  ("/StemV" . ,10)
          ;; When binary-data is not available, don't embded.
          ,@(when (and embed (binary-data t1fm))
              `(("/FontFile" . ,(make-instance 'indirect-object :content
                                  (make-instance 'pdf-stream
                                    :content (binary-data t1fm)
                                    :no-compression t ;(not *compress-fonts*)
                                    :dict-values `(;("/Type" . "/Pages") ;remove!
                                                   ("/Length1" . ,(length1 t1fm))
                                                   ("/Length2" . ,(length2 t1fm))
                                                   ("/Length3" . ,(length3 t1fm))
                                                   )))))))))))

;example of T1 font loading:
#+nil
(pdf:load-t1-font #P"/tmp/cmb10.afm" #P"/tmp/cmb10.pfb")
