-- NOTE: Untested!
module Graphics.Text.Font.Choose.FontSet where
import Graphics.Text.Font.Choose.Pattern
--import Graphics.Text.Font.Choose.Config
import Graphics.Text.Font.Choose.ObjectSet
import Graphics.Text.Font.Choose.Result (throwFalse, throwNull)
import Foreign.Ptr (Ptr, castPtr, nullPtr)
import Foreign.Storable (pokeElemOff, sizeOf, peek)
import Foreign.Marshal.Alloc (allocaBytes)
import Foreign.Marshal.Array (advancePtr)
import Control.Monad (forM)
import Control.Exception (bracket)
type FontSet = [Pattern]
{-fontSetList :: Config -> [FontSet] -> Pattern -> ObjectSet
fontSetList config fontss pattern objs = unsafePerformIO $ withConfig config $ \config' ->
withFontSets fontss $ \fontss' n -> withPattern $ \pattern' ->
withObjectSet objs $ \objs' ->
thawFontSet_ $ fcFontSetList config' fontss' n pattern' objs'
fontSetList' :: [FontSet] -> Pattern -> ObjectSet
fontSetList' fontss pattern objs = unsafePerformIO $ withFontSets fontss $ \fontss' n ->
withPattern $ \pattern' -> withObjectSet objs $ \objs' ->
thawFontSet_ $ fcFontSetList nullPtr fontss' n pattern' objs'
foreign import ccall "FcFontSetList" fcFontSetList ::
Config_ -> Ptr FontSet_ -> Int -> Pattern_ -> ObjectSet_ -> IO FontSet_
fontSetMatch :: Config -> [FontSet] -> Pattern -> Maybe Pattern
fontSetMatch config fontss pattern = withConfig config $ \config' ->
withFontSets fontss $ \fontss' -> withPattern $ \pattern' -> alloca $ \res' -> do
ret <- fcFontSetMatch config' fontss' n pattern' res'
throwPtr res' $ thawPattern_ $ pure ret
foreign import ccall "FcFontSetMatch" fcFontSetMatch ::
Config_ -> Ptr FontSet_ -> Int -> Pattern_ -> IO Pattern_
fontSetSort :: Config -> [FontSet] -> Pattern -> Bool -> CharSet -> Maybe FontSet
fontSetSort config fontss pattern trim csp cb = withConfig config $ \config' ->
withFontSets fontss $ \fontss' withPattern $ \pattern' ->
withCharSet csp $ \csp' -> alloca $ \res' -> do
ret' <- fcFontSetSort config' fontss' n pattern' trim csp' res'
throwPtr res' $ thawFontSet_ $ pure ret'
foreign import ccall "FcFontSetSort" fcFontSetSort ::
Config_ -> Ptr FontSet_ -> Int -> Pattern_ -> Bool -> CharSet_ -> Ptr Int -> IO FontSet_ -}
------
--- Low-level
------
type FontSet' = Int
type FontSet_ = Ptr FontSet'
withNewFontSet :: (FontSet_ -> IO a) -> IO a
withNewFontSet = bracket fcFontSetCreate fcFontSetDestroy
foreign import ccall "FcFontSetCreate" fcFontSetCreate :: IO FontSet_
foreign import ccall "FcFontSetDestroy" fcFontSetDestroy :: FontSet_ -> IO ()
withFontSet :: FontSet -> (FontSet_ -> IO a) -> IO a
withFontSet fonts cb = withNewFontSet $ \fonts' -> do
forM fonts $ \font -> do
font' <- patternAsPointer font
throwFalse <$> fcFontSetAdd fonts' font'
cb fonts'
foreign import ccall "FcFontSetAdd" fcFontSetAdd :: FontSet_ -> Pattern_ -> IO Bool
withFontSets :: [FontSet] -> (Ptr FontSet_ -> Int -> IO a) -> IO a
withFontSets fontss cb = let n = length fontss in
allocaBytes (sizeOf (undefined :: FontSet_) * n) $ \fontss' ->
withFontSets' fontss 0 fontss' $ cb fontss' n
withFontSets' :: [FontSet] -> Int -> Ptr FontSet_ -> IO a -> IO a
withFontSets' [] _ _ cb = cb
withFontSets' (fonts:fontss) i fontss' cb = withFontSet fonts $ \fonts' -> do
pokeElemOff fontss' i fonts'
withFontSets' fontss (succ i) fontss' cb
thawFontSet :: FontSet_ -> IO FontSet
thawFontSet fonts' = do
n <- peek fonts'
array <- peek $ castPtr $ advancePtr fonts' 2
if n == 0 || array == nullPtr
then return []
else forM [0..pred n] $ \i -> thawPattern =<< peek (advancePtr array i)
thawFontSet_ :: IO FontSet_ -> IO FontSet
thawFontSet_ cb = bracket (throwNull <$> cb) fcFontSetDestroy thawFontSet