opentype-0.0.1: Opentype/Fileformat/Types.hs
module Opentype.Fileformat.Types where
import Data.Word
import Data.Int
import Data.Bits
import Data.Binary.Put
import Data.ByteString.Unsafe
import qualified Data.ByteString as Strict
import qualified Data.Map as M
-- | A ShortFrac is an 16 bit signed fixed number with a bias of
-- 14. This means it can represent numbers between 1.999 (0x7fff) and
-- -2.0 (0x8000). 1.0 is stored as 16384 (0x4000) and -1.0 is stored
-- as -16384 (0xc000). Efficient numeric instances are provided.
newtype ShortFrac = ShortFrac Int16
-- | signed fixed-point number
type Fixed = Word32
-- | FWord describes a quantity in FUnits, the smallest
-- measurable distance in em space.
type FWord = Int16
-- | UFWord describes a quantity in FUnits, the smallest measurable
-- distance in em space.
type UFWord = Word16
-- | the glyph index in the glyph table
type GlyphID = Word16
data PlatformID =
UnicodePlatform |
-- | /DEPRECATED/
MacintoshPlatform |
MicrosoftPlatform
deriving (Ord, Eq, Show)
type WordMap a = M.Map Word32 a
-- return larged power of 2 <= i
iLog2 :: Integral a => a -> a
iLog2 = iLog2' 0 where
iLog2' base i
| i > 0 = iLog2' (base+1) (i `quot` 2)
| otherwise = base-1
byteAt :: (Bits a, Num a) => a -> Int -> Bool
byteAt flag i = flag .&. 1 `shift` i /= 0
{-# SPECIALIZE byteAt :: Word8 -> Int -> Bool #-}
{-# SPECIALIZE byteAt :: Word16 -> Int -> Bool #-}
makeFlag :: [Bool] -> Word16
makeFlag l =
fromIntegral $ sum $ zipWith (*) (iterate (*2) 1) $
map fromEnum l
instance Num ShortFrac where
(ShortFrac a) + (ShortFrac b) = ShortFrac $ a + b
(ShortFrac a) - (ShortFrac b) = ShortFrac $ a - b
(ShortFrac a) * (ShortFrac b) =
ShortFrac $ fromIntegral (((fromIntegral a :: Int32) * (fromIntegral b :: Int32)) `shift` (-14))
abs (ShortFrac a) = ShortFrac $ abs a
fromInteger i = ShortFrac $ fromIntegral i `shift` 14
signum (ShortFrac a) = fromIntegral $ signum a
instance Eq ShortFrac where
(ShortFrac a) == (ShortFrac b) = a == b
instance Ord ShortFrac where
compare (ShortFrac a) (ShortFrac b) = compare a b
instance Fractional ShortFrac where
fromRational r =
ShortFrac $ fromIntegral $
floor ((r+2) * 0x4000) - (0x8000::Word16)
(ShortFrac a) / (ShortFrac b) =
ShortFrac $ fromIntegral $
((fromIntegral a :: Int32) `shift` 14) `quot` fromIntegral b
instance Show ShortFrac where
show a = show (realToFrac a :: Float)
instance Real ShortFrac where
toRational (ShortFrac a) =
fromIntegral ((fromIntegral a::Word16) + 0x8000) / 0x4000 - 2
instance RealFrac ShortFrac where
properFraction (ShortFrac a)
| a < 0 && f /= 0 = (i+1, ShortFrac (-f))
| otherwise = (i, ShortFrac f)
where i = fromIntegral (((fromIntegral a :: Word16) + 0x8000) `shift` (-14)) - 2
f = a .&. 0x3fff
putShortFrac :: ShortFrac -> Put
putShortFrac (ShortFrac a) = putInt16be a
putPf :: PlatformID -> Put
putPf UnicodePlatform = putWord16be 0
putPf MacintoshPlatform = putWord16be 1
putPf MicrosoftPlatform = putWord16be 3
toPf :: Word16 -> Either String PlatformID
toPf i =
case i of
0 -> Right UnicodePlatform
1 -> Right MacintoshPlatform
3 -> Right MicrosoftPlatform
j -> Left $ "unknown platformID " ++ show j
index16 :: Strict.ByteString -> Word16 -> Either String Word16
index16 bs i
| Strict.length bs < fromIntegral ((i+1)*2) ||
i < 0 = Left $ "Index " ++ show i ++ " out of Bounds"
| otherwise = Right $ b1 * 256 + b2
where
b1, b2 :: Word16
b1 = fromIntegral $ unsafeIndex bs (fromIntegral $ i*2)
b2 = fromIntegral $ unsafeIndex bs (fromIntegral $ i*2 + 1)
index32 :: Strict.ByteString -> Word32 -> Either String Word32
index32 bs i
| Strict.length bs < fromIntegral ((i+1)*4) ||
i < 0 = Left $ "Index " ++ show i ++ " Out of Bounds"
| otherwise = Right $ b1 `shift` 24 .|. b2 `shift` 16 .|. b3 `shift` 8 .|. b4
where
b1, b2, b3, b4 :: Word32
b1 = fromIntegral $ unsafeIndex bs (fromIntegral $ i*4)
b2 = fromIntegral $ unsafeIndex bs (fromIntegral $ i*4 + 1)
b3 = fromIntegral $ unsafeIndex bs (fromIntegral $ i*4 + 2)
b4 = fromIntegral $ unsafeIndex bs (fromIntegral $ i*4 + 3)