-- 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