module Opentype.Fileformat.Head where
import Opentype.Fileformat.Types
import Data.Time
import Data.Binary
import Data.Binary.Get
import Data.Binary.Put
import Control.Monad
import Data.Int
data HeadTable = HeadTable {
headVersion :: Fixed,
fontRevision :: Fixed,
baselineYZero :: Bool,
sidebearingXZero :: Bool,
pointsizeDepend :: Bool,
integerScaling :: Bool,
alterAdvanceWidth :: Bool,
verticalFont :: Bool,
linguisticRenderingLayout :: Bool,
metamorphosisEffects :: Bool,
rightToLeftGlyphs :: Bool,
indicRearrangements :: Bool,
losslessFontData :: Bool,
convertedFont :: Bool,
clearTypeOptimized :: Bool,
lastResortFont :: Bool,
unitsPerEm :: Word16,
created :: UTCTime, modified :: UTCTime,
xMin :: FWord,
yMin :: FWord,
xMax :: FWord,
yMax :: FWord,
boldStyle :: Bool,
italicStyle :: Bool,
underlineStyle :: Bool,
outlineStyle :: Bool,
shadowStyle :: Bool,
condensedStyle :: Bool,
extendedStyle :: Bool,
lowerRecPPEM :: Word16,
fontDirectionHint :: Int16,
longLocIndices :: Bool,
glyphDataFormat :: Int16
}
deriving Show
getHeadTable :: Get HeadTable
getHeadTable = do
major <- getWord16be
minor <- getWord16be
when (major /= 1 && minor /= 0)
(fail "Invalid head table")
revision <- getWord32be
_ <- getWord32be
magic <- getWord32be
when (magic /= 0x5F0F3CF5)
(fail "Invalid magic value in head table")
flags <- getWord16be
uPe <- getWord16be
created_ <- getInt64be
modified_ <- getInt64be
xMin_ <- getInt16be
yMin_ <- getInt16be
xMax_ <- getInt16be
yMax_ <- getInt16be
mcStyle <- getWord16be
lRec <- getWord16be
fDir <- getInt16be
iToL <- getInt16be
gd <- getInt16be
let flagAt = byteAt flags
styleAt = byteAt mcStyle
return $ HeadTable 0x00010000 revision
(flagAt 0) (flagAt 1) (flagAt 2) (flagAt 3)
(flagAt 4) (flagAt 5) (flagAt 7) (flagAt 8) (flagAt 9)
(flagAt 10) (flagAt 11) (flagAt 12) (flagAt 13) (flagAt 14)
uPe (getTime created_) (getTime modified_)
xMin_ yMin_ xMax_ yMax_
(styleAt 0) (styleAt 1) (styleAt 2) (styleAt 3) (styleAt 4)
(styleAt 5) (styleAt 6) lRec fDir (iToL /= 0) gd
putHeadTable :: HeadTable -> Put
putHeadTable headTbl = do
putWord16be 1
putWord16be 0
putWord32be $ fontRevision headTbl
putWord32be 0
putWord32be 0x5F0F3CF5
putWord16be $ makeFlag $ map ($ headTbl)
[baselineYZero, sidebearingXZero, pointsizeDepend, integerScaling, alterAdvanceWidth,
const False, verticalFont, linguisticRenderingLayout, metamorphosisEffects, rightToLeftGlyphs,
indicRearrangements, losslessFontData, convertedFont, clearTypeOptimized, lastResortFont, const False]
putWord16be $ unitsPerEm headTbl
putInt64be $ putTime $ created headTbl
putInt64be $ putTime $ modified headTbl
putInt16be $ xMin headTbl
putInt16be $ yMin headTbl
putInt16be $ xMax headTbl
putInt16be $ yMax headTbl
putWord16be $ makeFlag $ map ($ headTbl)
[boldStyle, italicStyle, underlineStyle, outlineStyle, shadowStyle, condensedStyle, extendedStyle]
putWord16be $ lowerRecPPEM headTbl
putInt16be 2
putInt16be $ fromIntegral $ fromEnum $ longLocIndices headTbl
putInt16be 0
secDay :: Int64
secDay = 60 * 60 * 24
diffSeconds :: Int64
diffSeconds =
secDay * fromIntegral (fromGregorian 1858 11 17 `diffDays` fromGregorian 1904 1 1)
getTime :: Int64 -> UTCTime
getTime secs = UTCTime (ModifiedJulianDay $ fromIntegral d) (secondsToDiffTime $ fromIntegral t)
where (d,t) = (secs diffSeconds) `quotRem` fromIntegral secDay
putTime :: UTCTime -> Int64
putTime (UTCTime (ModifiedJulianDay d) t) =
fromIntegral d * secDay + diffTimeToSeconds t + diffSeconds
diffTimeToSeconds :: DiffTime -> Int64
diffTimeToSeconds d =
fromIntegral $ diffTimeToPicoseconds d `quot` 1000000000