{-# LANGUAGE CPP, ForeignFunctionInterface #-}
{-# CFILES cbits/wrapper.c #-}
module Graphics.Rendering.TrueType.STB
( TrueType(..)
, Offset
, Font(..)
, CFontInfo
, Glyph
, loadTTF
, withTTF
, enumerateFonts
, initFont
, findGlyph
, notDefinedGlyphChar
, Unscaled
, Scaling
, HorizontalMetrics(..)
, VerticalMetrics(..)
, BoundingBox(..)
, lineAdvance
, verticalSize
, scaleForPixelHeight
, getFontVerticalMetrics
, getGlyphHorizontalMetrics
, getGlyphKernAdvance
, getGlyphBoundingBox
, Bitmap(..)
, newBitmap
, withBitmap
, flipBitmap
, BitmapOfs
, bitmapArray
, bitmapFloatArray
, getGlyphBitmapBox
, newGlyphBitmap
, renderGlyphIntoBitmap'
, renderGlyphIntoBitmap
, SubpixelShift
, getGlyphBitmapBoxSubpixel
, newGlyphBitmapSubpixel
, renderGlyphIntoBitmapSubpixel'
, renderGlyphIntoBitmapSubpixel
, CachedBitmap(..)
, BitmapCache(..)
, bmcVerticalMetrics
, bmcScaling
, newBitmapCache
, getCachedBitmap
, UnicodeCache
, newUnicodeCache
, lookupUnicodeCache
)
where
import Control.Monad
import Control.Applicative
import Control.Concurrent.MVar
import Data.Char
import Data.Maybe
import Data.Array
import Data.Array.IO
import Data.Array.Unboxed
import Data.Array.Unsafe
#ifdef __GLASGOW_HASKELL__
import qualified Data.Array.Base as Arr
#endif
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Foreign hiding (newArray)
import Foreign.C
import Foreign.Concurrent
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as BI
import System.IO.Unsafe as Unsafe
newtype TrueType = TrueType ByteString
newtype Offset = Offset Int deriving (Eq,Ord,Show)
newtype Glyph = Glyph Int deriving (Eq,Ord,Show)
notdefGlyph :: Glyph
notdefGlyph = Glyph 0
ccodepoint :: Char -> CCodepoint
ccodepoint = fromIntegral . ord
cglyphindex :: Glyph -> CGlyphIndex
cglyphindex (Glyph i) = fromIntegral i
withTrueType :: TrueType -> (Ptr Word8 -> IO a) -> IO a
withTrueType (TrueType bs) action = withByteString bs action
withByteString :: ByteString -> (Ptr Word8 -> IO a) -> IO a
withByteString bs action = withForeignPtr fptr h where
(fptr,ofs,len) = BI.toForeignPtr bs
h p = action (plusPtr p ofs)
data Font = Font
{ _fontData :: TrueType
, _fontInfo :: ForeignPtr CFontInfo
, _glyphMap :: UnicodeCache (Maybe Glyph)
}
withFontInfo :: Font -> (Ptr CFontInfo -> IO a) -> IO a
withFontInfo (Font _ fptr _) = withForeignPtr fptr
newtype UnicodeCache a = UC (MVar (IntMap (IOArray Char (Maybe a))))
unicodeCacheGranularity :: Int
unicodeCacheGranularity = 128
newUnicodeCache :: IO (UnicodeCache a)
newUnicodeCache = UC <$> newMVar (IntMap.empty)
lookupUnicodeCache :: Char -> (Char -> IO a) -> UnicodeCache a -> IO a
lookupUnicodeCache char calculate (UC cache) = do
themap <- takeMVar cache
let k = ord char `div` unicodeCacheGranularity
case IntMap.lookup k themap of
Just arr -> do
putMVar cache themap
mvalue <- readArray arr char
case mvalue of
Just value -> do
return value
Nothing -> do
new <- calculate char
writeArray arr char (Just new)
return new
Nothing -> do
let u = k*unicodeCacheGranularity
let v = u + unicodeCacheGranularity - 1
arr <- newArray (chr u, chr v) Nothing
new <- calculate char
writeArray arr char (Just new)
putMVar cache (IntMap.insert k arr themap)
return new
enumerateFonts :: TrueType -> IO [Offset]
enumerateFonts ttf = withTrueType ttf $ \ptr -> worker ptr 0 where
worker ptr i = do
o <- fromIntegral <$> stbtt_GetFontOffsetForIndex ptr i
if o < 0
then return []
else do
os <- worker ptr (i+1)
return (Offset o : os)
initFont :: TrueType -> Offset -> IO Font
initFont ttf (Offset ofs) = withTrueType ttf $ \ptr -> do
fq <- mallocForeignPtr :: IO (ForeignPtr CFontInfo)
withForeignPtr fq $ \q -> stbtt_InitFont q ptr (fromIntegral ofs)
mglyphmap <- newUnicodeCache
return (Font ttf fq mglyphmap)
loadTTF :: FilePath -> IO TrueType
loadTTF fname = do
bs <- B.readFile fname
return (TrueType bs)
withTTF :: FilePath -> (TrueType -> IO a) -> IO a
withTTF fname action = do
bs <- B.readFile fname
action (TrueType bs)
notDefinedGlyphChar :: Char
notDefinedGlyphChar = '\xffff'
findGlyph :: Font -> Char -> IO (Maybe Glyph)
findGlyph fontinfo@(Font _ _ glyphmap) char =
case ord char of
0xffff -> return (Just notdefGlyph)
_ -> lookupUnicodeCache char (findGlyphNotCached fontinfo) glyphmap
findGlyphNotCached :: Font -> Char -> IO (Maybe Glyph)
findGlyphNotCached fontinfo char =
withFontInfo fontinfo $ \ptr -> do
let codepoint = ord char
i <- stbtt_FindGlyphIndex ptr (fromIntegral codepoint)
if i == 0
then return Nothing
else do
let glyph = Glyph (fromIntegral i)
return (Just glyph)
data CachedBitmap = CBM !Glyph !Bitmap !BitmapOfs !(HorizontalMetrics Float)
data BitmapCache = BMCache
{ bmc_fontinfo :: !Font
, bmc_scaling :: !(Float,Float)
, bmc_cache :: !(UnicodeCache (Maybe CachedBitmap))
, bmc_vmetrics :: !(VerticalMetrics Float)
, bmc_flipped :: !Bool
}
bmcVerticalMetrics :: BitmapCache -> VerticalMetrics Float
bmcVerticalMetrics = bmc_vmetrics
bmcScaling :: BitmapCache -> Scaling
bmcScaling = bmc_scaling
newBitmapCache :: Font -> Bool -> (Float,Float) -> IO BitmapCache
newBitmapCache fontinfo flipped scaling@(xscale,yscale) = do
cache <- newUnicodeCache
vmetu <- getFontVerticalMetrics fontinfo
let vmets = fmap (\y -> yscale * fromIntegral y) vmetu
return $ BMCache fontinfo scaling cache vmets flipped
getCachedBitmap :: BitmapCache -> Char -> IO (Maybe CachedBitmap)
getCachedBitmap (BMCache font scaling@(xscale,yscale) cache vmet flipped) char =
lookupUnicodeCache char createBitmap cache
where
createBitmap char = do
mglyph <- findGlyph font char
case mglyph of
Just glyph -> do
(bm',ofs) <- newGlyphBitmap font glyph scaling
bm <- if flipped then flipBitmap bm' else return bm'
hmetu <- getGlyphHorizontalMetrics font glyph
let hmets = fmap (\x -> xscale * fromIntegral x) hmetu
return $ Just (CBM glyph bm ofs hmets)
Nothing -> do
return Nothing
type Unscaled = Int
data VerticalMetrics a = VMetrics
{ ascent :: !a
, descent :: !a
, lineGap :: !a
}
deriving Show
instance Functor VerticalMetrics where
fmap f (VMetrics a d l) = VMetrics (f a) (f d) (f l)
lineAdvance :: Num a => VerticalMetrics a -> a
lineAdvance vm = ascent vm - descent vm + lineGap vm
verticalSize :: Num a => VerticalMetrics a -> a
verticalSize vm = ascent vm - descent vm
scaleForPixelHeight :: VerticalMetrics Unscaled -> Float -> Float
scaleForPixelHeight vm pixels = pixels / fromIntegral (verticalSize vm)
data HorizontalMetrics a = HMetrics
{ advanceWidth :: !a
, leftSideBearing :: !a
}
deriving Show
instance Functor HorizontalMetrics where
fmap f (HMetrics a l) = HMetrics (f a) (f l)
data BoundingBox a = BBox (a,a) (a,a) deriving Show
getFontVerticalMetrics :: Font -> IO (VerticalMetrics Unscaled)
getFontVerticalMetrics fontinfo =
withFontInfo fontinfo $ \ptr -> do
alloca $ \pasc -> alloca $ \pdesc -> alloca $ \pgap -> do
stbtt_GetFontVMetrics ptr pasc pdesc pgap
asc <- peek pasc :: IO CInt
desc <- peek pdesc :: IO CInt
gap <- peek pgap :: IO CInt
return $ VMetrics
{ ascent = fromIntegral asc
, descent = fromIntegral desc
, lineGap = fromIntegral gap
}
getGlyphHorizontalMetrics :: Font -> Glyph -> IO (HorizontalMetrics Unscaled)
getGlyphHorizontalMetrics fontinfo glyph =
withFontInfo fontinfo $ \ptr -> do
alloca $ \padv -> alloca $ \plsb -> do
stbtt_GetGlyphHMetrics ptr (cglyphindex glyph) padv plsb
adv <- peek padv :: IO CInt
lsb <- peek plsb :: IO CInt
return $ HMetrics
{ advanceWidth = fromIntegral adv
, leftSideBearing = fromIntegral lsb
}
getGlyphKernAdvance :: Font -> Glyph -> Glyph -> IO Unscaled
getGlyphKernAdvance fontinfo glyph1 glyph2 =
withFontInfo fontinfo $ \ptr -> do
kern <- stbtt_GetGlyphKernAdvance ptr (cglyphindex glyph1) (cglyphindex glyph1)
return (fromIntegral kern)
getGlyphBoundingBox :: Font -> Glyph -> IO (Maybe (BoundingBox Unscaled))
getGlyphBoundingBox fontinfo glyph =
withFontInfo fontinfo $ \ptr -> do
alloca $ \px0 -> alloca $ \py0 -> alloca $ \px1 -> alloca $ \py1 -> do
r <- stbtt_GetGlyphBox ptr (cglyphindex glyph) px0 py0 px1 py1
if r == 0
then return Nothing
else do
x0 <- peek px0 :: IO CInt
y0 <- peek py0 :: IO CInt
x1 <- peek px1 :: IO CInt
y1 <- peek py1 :: IO CInt
return $ Just $ BBox
(fromIntegral x0, fromIntegral y0)
(fromIntegral x1, fromIntegral y1)
type Scaling = (Float,Float)
data Bitmap = Bitmap
{ bitmapSize :: !(Int,Int)
, bitmapPtr :: !(ForeignPtr Word8)
}
type BitmapOfs = (Int,Int)
newBitmap :: (Int,Int) -> IO Bitmap
newBitmap siz@(xsiz,ysiz) = do
let n = xsiz*ysiz
fptr <- mallocForeignPtrBytes n
withForeignPtr fptr $ \ptr -> pokeArray ptr (replicate n 0)
return (Bitmap siz fptr)
withBitmap :: Bitmap -> (Int -> Int -> Ptr Word8 -> IO a) -> IO a
withBitmap bm action = do
let (xsiz,ysiz) = bitmapSize bm
withForeignPtr (bitmapPtr bm) $ \ptr -> action xsiz ysiz ptr
flipBitmap :: Bitmap -> IO Bitmap
flipBitmap (Bitmap siz@(xsiz,ysiz) fptr1) = withForeignPtr fptr1 $ \ptr1 -> do
let n = xsiz*ysiz
fptr2 <- mallocForeignPtrBytes n
withForeignPtr fptr2 $ \ptr2 -> do
forM_ [0..ysiz-1] $ \y1 -> do
let y2 = ysiz-1-y1
copyBytes (ptr2 `plusPtr` (y2*xsiz)) (ptr1 `plusPtr` (y1*xsiz)) xsiz
return (Bitmap siz fptr2)
bitmapArray :: Bitmap -> IO (UArray (Int,Int) Word8)
bitmapArray bm =
withBitmap bm $ \xsiz ysiz ptr -> do
ar <- newArray_ ((0,0),(ysiz-1,xsiz-1)) :: IO (IOUArray (Int,Int) Word8)
forM_ [0..ysiz-1] $ \y -> do
let k = y*xsiz
forM_ [0..xsiz-1] $ \x -> do
a <- peekElemOff ptr (k+x)
#ifdef __GLASGOW_HASKELL__
Arr.unsafeWrite ar (k+x) a
#else
writeArray ar (y,x) a
#endif
Arr.unsafeFreeze ar
bitmapFloatArray :: Bitmap -> IO (UArray (Int,Int) Float)
bitmapFloatArray bm =
withBitmap bm $ \xsiz ysiz ptr -> do
let factor = 1.0 / 255 :: Float
ar <- newArray_ ((0,0),(ysiz-1,xsiz-1)) :: IO (IOUArray (Int,Int) Float)
forM_ [0..ysiz-1] $ \y -> do
let k = y*xsiz
forM_ [0..xsiz-1] $ \x -> do
a <- peekElemOff ptr (k+x)
let z = fromIntegral a * factor
#ifdef __GLASGOW_HASKELL__
Arr.unsafeWrite ar (k+x) z
#else
writeArray ar (y,x) z
#endif
Arr.unsafeFreeze ar
getGlyphBitmapBox :: Font -> Glyph -> Scaling -> IO (BoundingBox Int)
getGlyphBitmapBox fontinfo glyph (xscale,yscale) =
withFontInfo fontinfo $ \ptr -> do
alloca $ \px0 -> alloca $ \py0 -> alloca $ \px1 -> alloca $ \py1 -> do
stbtt_GetGlyphBitmapBox ptr (cglyphindex glyph) (realToFrac xscale) (realToFrac yscale) px0 py0 px1 py1
x0 <- peek px0 :: IO CInt
y0 <- peek py0 :: IO CInt
x1 <- peek px1 :: IO CInt
y1 <- peek py1 :: IO CInt
return $ BBox
(fromIntegral x0, fromIntegral y0)
(fromIntegral x1, fromIntegral y1)
newGlyphBitmap :: Font -> Glyph -> Scaling -> IO (Bitmap,BitmapOfs)
newGlyphBitmap fontinfo glyph (xscale,yscale) = do
withFontInfo fontinfo $ \ptr -> do
alloca $ \pxsiz -> alloca $ \pysiz -> alloca $ \pxofs -> alloca $ \pyofs -> do
pbm <- stbtt_GetGlyphBitmap ptr
(realToFrac xscale) (realToFrac yscale)
(cglyphindex glyph)
pxsiz pysiz pxofs pyofs
xsiz <- peek pxsiz :: IO CInt
ysiz <- peek pysiz :: IO CInt
xofs <- peek pxofs :: IO CInt
yofs <- peek pyofs :: IO CInt
fpbm <- Foreign.Concurrent.newForeignPtr pbm (bitmapFinalizer1 pbm)
let bm = Bitmap (fromIntegral xsiz, fromIntegral ysiz) fpbm
ofs = (fromIntegral xofs, fromIntegral yofs)
return $ (bm,ofs)
renderGlyphIntoBitmap' :: Font -> Glyph -> Scaling -> Bitmap -> BitmapOfs -> IO ()
renderGlyphIntoBitmap' fontinfo glyph (xscale,yscale) bm (xofs,yofs) = do
let (xsiz,ysiz) = bitmapSize bm
when ( xofs < xsiz && yofs < ysiz && xofs >= 0 && yofs >= 0 ) $ do
withFontInfo fontinfo $ \ptr -> do
withBitmap bm $ \width height pbm -> do
let pbm' = pbm `plusPtr` (width*yofs+xofs)
stbtt_MakeGlyphBitmap ptr pbm'
(fromIntegral $ width - xofs) (fromIntegral $ height - yofs)
(fromIntegral width)
(realToFrac xscale) (realToFrac yscale)
(cglyphindex glyph)
renderGlyphIntoBitmap :: Font -> Glyph -> Scaling -> Bitmap -> BitmapOfs -> IO ()
renderGlyphIntoBitmap fontinfo glyph scaling@(xscale,yscale) bm ofs@(xofs,yofs) = do
BBox (x0,y0) _ <- getGlyphBitmapBox fontinfo glyph scaling
renderGlyphIntoBitmap' fontinfo glyph scaling bm (xofs+x0,yofs+y0)
type SubpixelShift = (Float,Float)
getGlyphBitmapBoxSubpixel :: Font -> Glyph -> Scaling -> SubpixelShift -> IO (BoundingBox Int)
getGlyphBitmapBoxSubpixel fontinfo glyph (xscale,yscale) (xshift,yshift) =
withFontInfo fontinfo $ \ptr -> do
alloca $ \px0 -> alloca $ \py0 -> alloca $ \px1 -> alloca $ \py1 -> do
stbtt_GetGlyphBitmapBoxSubpixel ptr (cglyphindex glyph)
(realToFrac xscale) (realToFrac yscale)
(realToFrac xshift) (realToFrac yshift)
px0 py0 px1 py1
x0 <- peek px0 :: IO CInt
y0 <- peek py0 :: IO CInt
x1 <- peek px1 :: IO CInt
y1 <- peek py1 :: IO CInt
return $ BBox
(fromIntegral x0, fromIntegral y0)
(fromIntegral x1, fromIntegral y1)
newGlyphBitmapSubpixel :: Font -> Glyph -> Scaling -> SubpixelShift -> IO (Bitmap,BitmapOfs)
newGlyphBitmapSubpixel fontinfo glyph (xscale,yscale) (xshift,yshift) = do
withFontInfo fontinfo $ \ptr -> do
alloca $ \pxsiz -> alloca $ \pysiz -> alloca $ \pxofs -> alloca $ \pyofs -> do
pbm <- stbtt_GetGlyphBitmapSubpixel ptr
(realToFrac xscale) (realToFrac yscale)
(realToFrac xshift) (realToFrac yshift)
(cglyphindex glyph)
pxsiz pysiz pxofs pyofs
xsiz <- peek pxsiz :: IO CInt
ysiz <- peek pysiz :: IO CInt
xofs <- peek pxofs :: IO CInt
yofs <- peek pyofs :: IO CInt
fpbm <- Foreign.Concurrent.newForeignPtr pbm (bitmapFinalizer1 pbm)
let bm = Bitmap (fromIntegral xsiz, fromIntegral ysiz) fpbm
ofs = (fromIntegral xofs, fromIntegral yofs)
return $ (bm,ofs)
renderGlyphIntoBitmapSubpixel' :: Font -> Glyph -> Scaling -> SubpixelShift -> Bitmap -> BitmapOfs -> IO ()
renderGlyphIntoBitmapSubpixel' fontinfo glyph (xscale,yscale) (xshift,yshift) bm (xofs,yofs) = do
let (xsiz,ysiz) = bitmapSize bm
when ( xofs < xsiz && yofs < ysiz && xofs >= 0 && yofs >= 0 ) $ do
withFontInfo fontinfo $ \ptr -> do
withBitmap bm $ \width height pbm -> do
let pbm' = pbm `plusPtr` (width*yofs+xofs)
stbtt_MakeGlyphBitmapSubpixel ptr pbm'
(fromIntegral $ width - xofs) (fromIntegral $ height - yofs)
(fromIntegral width)
(realToFrac xscale) (realToFrac yscale)
(realToFrac xshift) (realToFrac yshift)
(cglyphindex glyph)
renderGlyphIntoBitmapSubpixel :: Font -> Glyph -> Scaling -> SubpixelShift -> Bitmap -> BitmapOfs -> IO ()
renderGlyphIntoBitmapSubpixel fontinfo glyph scaling@(xscale,yscale) shift bm ofs@(xofs,yofs) = do
BBox (x0,y0) _ <- getGlyphBitmapBoxSubpixel fontinfo glyph scaling shift
renderGlyphIntoBitmapSubpixel' fontinfo glyph scaling shift bm (xofs+x0,yofs+y0)
foreign import ccall "sizeof_stbtt_fontinfo" sizeof_stbtt_fontinfo :: CInt
data CFontInfo = CFontInfo
instance Storable CFontInfo where
alignment _ = alignment (undefined :: CInt)
sizeOf _ = fromIntegral sizeof_stbtt_fontinfo
peek = error "CFontInfo/peek: not implemented"
poke = error "CFontInfo/poke: not implemented"
type CCodepoint = CInt
type CGlyphIndex = CInt
foreign import ccall unsafe "stb_truetype.h stbtt_GetFontOffsetForIndex"
stbtt_GetFontOffsetForIndex :: Ptr Word8 -> CInt -> IO CInt
foreign import ccall unsafe "stb_truetype.h stbtt_InitFont"
stbtt_InitFont :: Ptr CFontInfo -> Ptr Word8 -> CInt -> IO CInt
foreign import ccall unsafe "stb_truetype.h stbtt_FindGlyphIndex"
stbtt_FindGlyphIndex :: Ptr CFontInfo -> CCodepoint -> IO CGlyphIndex
foreign import ccall unsafe "stb_truetype.h stbtt_GetFontVMetrics"
stbtt_GetFontVMetrics :: Ptr CFontInfo -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO ()
foreign import ccall unsafe "stb_truetype.h stbtt_GetGlyphHMetrics"
stbtt_GetGlyphHMetrics :: Ptr CFontInfo -> CGlyphIndex -> Ptr CInt -> Ptr CInt -> IO ()
foreign import ccall unsafe "stb_truetype.h stbtt_GetGlyphKernAdvance"
stbtt_GetGlyphKernAdvance :: Ptr CFontInfo -> CGlyphIndex -> CGlyphIndex -> IO CInt
foreign import ccall unsafe "stb_truetype.h stbtt_GetGlyphBox"
stbtt_GetGlyphBox
:: Ptr CFontInfo -> CGlyphIndex -> Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO CInt
foreign import ccall unsafe "stb_truetype.h stbtt_FreeBitmap"
stbtt_FreeBitmap :: Ptr Word8 -> Ptr a -> IO ()
foreign import ccall "wrapper" mkFinPtr
:: (Ptr Word8 -> IO ()) -> IO (FinalizerPtr Word8)
bitmapFinalizer :: FunPtr (Ptr Word8 -> IO ())
bitmapFinalizer = Unsafe.unsafePerformIO $ mkFinPtr $ \p -> stbtt_FreeBitmap p nullPtr
bitmapFinalizer1 :: Ptr Word8 -> IO ()
bitmapFinalizer1 p = stbtt_FreeBitmap p nullPtr
foreign import ccall unsafe "stb_truetype.h stbtt_GetGlyphBitmap"
stbtt_GetGlyphBitmap
:: Ptr CFontInfo -> CFloat -> CFloat -> CGlyphIndex
-> Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO (Ptr Word8)
foreign import ccall unsafe "stb_truetype.h stbtt_MakeGlyphBitmap"
stbtt_MakeGlyphBitmap
:: Ptr CFontInfo -> Ptr Word8 -> CInt -> CInt -> CInt
-> CFloat -> CFloat -> CGlyphIndex -> IO ()
foreign import ccall unsafe "stb_truetype.h stbtt_GetGlyphBitmapBox"
stbtt_GetGlyphBitmapBox
:: Ptr CFontInfo -> CGlyphIndex -> CFloat -> CFloat
-> Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO ()
foreign import ccall unsafe "stb_truetype.h stbtt_GetGlyphBitmapSubpixel"
stbtt_GetGlyphBitmapSubpixel
:: Ptr CFontInfo -> CFloat -> CFloat
-> CFloat -> CFloat
-> CGlyphIndex
-> Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO (Ptr Word8)
foreign import ccall unsafe "stb_truetype.h stbtt_MakeGlyphBitmap"
stbtt_MakeGlyphBitmapSubpixel
:: Ptr CFontInfo -> Ptr Word8 -> CInt -> CInt -> CInt
-> CFloat -> CFloat
-> CFloat -> CFloat
-> CGlyphIndex -> IO ()
foreign import ccall unsafe "stb_truetype.h stbtt_GetGlyphBitmapBoxSubpixel"
stbtt_GetGlyphBitmapBoxSubpixel
:: Ptr CFontInfo -> CGlyphIndex -> CFloat -> CFloat
-> CFloat -> CFloat
-> Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO ()