-------------------------------------------------------------------------------- -- Copyright 1994 by Peter Thiemann -- $Log: Fonts.hs,v $ -- Revision 1.1 2004/08/05 11:11:58 malcolm -- Add a regression testsuite for the nhc98 compiler. It isn't very good, -- but it is better than nothing. I've been using it for about four years -- on nightly builds, so it's about time it entered the repository! It -- includes a slightly altered version of the nofib suite. -- Instructions are in the README. -- -- Revision 1.7 2000/01/24 17:14:26 simonmar -- Undo fromInt changes: already converted to fromIntegral. -- -- Revision 1.6 1999/12/08 09:56:37 simonmar -- -syslib updates for new libraries. -- -- Revision 1.5 1999/11/26 10:29:54 simonpj -- fromInt wibble -- -- Revision 1.4 1999/09/14 10:18:24 simonmar -- Replace all instances of fromInt in nofib with fromIntegral. -- -- We generate the same code in most cases :-) -- -- Revision 1.3 1997/03/14 08:08:05 simonpj -- Major update to more-or-less 2.02 -- -- Revision 1.2 1996/07/25 21:23:54 partain -- Bulk of final changes for 2.01 -- -- Revision 1.1 1996/01/08 20:02:33 partain -- Initial revision -- -- Revision 1.1 1993/08/31 12:31:32 thiemann -- Initial revision -- -- Revision 1.1 1993/08/31 12:31:32 thiemann -- Initial revision -- -- $Locker: $ -------------------------------------------------------------------------------- module Fonts (FONT, makeFont, fontDescender, stringWidth, stringHeight, fontName, fontScale, noFont) where import Char--1.3 -- not in 1.3 readDec :: (Integral a) => ReadS a readDec = readInt 10 isDigit (\d -> ord d - ord_0) readInt :: (Integral a) => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a readInt radix isDig digToInt s = [(foldl1 (\n d -> n * radix + d) (map (fromIntegral . digToInt) ds), r) | (ds,r) <- nonnull isDig s ] ord_0 :: Num a => a ord_0 = fromIntegral (ord '0') nonnull :: (Char -> Bool) -> ReadS String nonnull p s = [(cs,t) | (cs@(_:_),t) <- [span p s]] readSigned :: (Real a) => ReadS a -> ReadS a readSigned readPos = readParen False read' where read' r = read'' r ++ [(-x,t) | ("-",s) <- lex r, (x,t) <- read'' s] read'' r = [(n,s) | (str,s) <- lex r, (n,"") <- readPos str] data FONT = FONT String Int Int (String -> Int) instance Eq FONT where FONT s1 m1 n1 f1 == FONT s2 m2 n2 f2 = s1 == s2 && m1 == m2 && n1 == n2 noFont = FONT "" 0 0 (const 0) data Afm = Descender Int | CharMetric Int Int String Int Int Int Int -- CharMetric charNo charWX charName llx lly urx ury -- deriving Text fontName :: FONT -> String fontName (FONT name _ _ _) = name fontScale :: FONT -> Int fontScale (FONT _ scale _ _) = scale fontDescender :: FONT -> Int fontDescender (FONT _ _ theDescender _) = theDescender stringWidth :: FONT -> String -> Int stringWidth (FONT _ _ _ theStringWidth) = theStringWidth stringHeight :: FONT -> String -> Int stringHeight (FONT _ scale _ _) _ = scale * 100 makeFont :: String -> Int -> String -> FONT makeFont fontName fontScale fontAfm = FONT fontName fontScale theDescender ((`div` 10). (* fontScale). getStringWidth parsedAfm) where parsedAfm = parseAfmFile (lines fontAfm) theDescender = getDescender parsedAfm getStringWidth :: [Afm] -> String -> Int getStringWidth afms str = sum (map (getCharWidth afms . fromEnum) str) getCharWidth :: [Afm] -> Int -> Int getCharWidth (CharMetric charNo charWX charName llx lly urx ury: afms) chNo | charNo == chNo = charWX | otherwise = getCharWidth afms chNo getCharWidth (_:afms) chNo = getCharWidth afms chNo getCharWidth [] chNo = 0 getDescender :: [Afm] -> Int getDescender (Descender d: _) = d getDescender (_:rest) = getDescender rest getDescender [] = 0 -------------------------------------------------------------------------------- parseAfmFile :: [String] -> [Afm] parseAfmFile [] = [] parseAfmFile (('D':'e':'s':'c':'e':'n':'d':'e':'r':line):lines) = Descender descender: parseAfmFile lines where (descender,_):_ = readSigned readDec (skipWhite line) parseAfmFile (('E':'n':'d':'C':'h':'a':'r':'M':'e':'t':'r':'i':'c':'s':_):_) = [] parseAfmFile (('C':' ':line):lines) = CharMetric charNo charWX charName llx lly urx ury: parseAfmFile lines where (charNo, rest1):_ = readSigned readDec (skipWhite line) 'W':'X':rest2 = skipWhiteOrSemi rest1 (charWX, rest3):_ = readDec (skipWhite rest2) 'N':rest4 = skipWhiteOrSemi rest3 (charName, rest5) = span isAlpha (skipWhite rest4) 'B':rest6 = skipWhiteOrSemi rest5 (llx, rest7):_ = readSigned readDec (skipWhite rest6) (lly, rest8):_ = readSigned readDec (skipWhite rest7) (urx, rest9):_ = readSigned readDec (skipWhite rest8) (ury, _):_ = readSigned readDec (skipWhite rest9) parseAfmFile (_:lines) = parseAfmFile lines skipWhite = dropWhile isSpace skipWhiteOrSemi = dropWhile isSkipChar isSkipChar c = isSpace c || c == ';'