module Termtab.Graphics.Font (
GlyphFont,
bravuraFontPath,
openGlyphFont,
withGlyphFont,
closeGlyphFont,
cachedGlyph,
) where
import Control.Exception (bracket)
import Data.IORef
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import System.Environment (lookupEnv)
import Termtab.Graphics.FreeType
data GlyphFont = GlyphFont
{ GlyphFont -> FontFace
gfFace :: FontFace
, GlyphFont -> IORef (Map (Int, Char) (Maybe GlyphBitmap))
gfCache :: IORef (Map (Int, Char) (Maybe GlyphBitmap))
}
bravuraFontPath :: IO (Maybe FilePath)
bravuraFontPath :: IO (Maybe FilePath)
bravuraFontPath = FilePath -> IO (Maybe FilePath)
lookupEnv FilePath
"TERMTAB_BRAVURA_FONT"
openGlyphFont :: FilePath -> IO GlyphFont
openGlyphFont :: FilePath -> IO GlyphFont
openGlyphFont FilePath
path = do
face <- FilePath -> IO FontFace
newFontFace FilePath
path
ref <- newIORef Map.empty
pure (GlyphFont face ref)
closeGlyphFont :: GlyphFont -> IO ()
closeGlyphFont :: GlyphFont -> IO ()
closeGlyphFont = FontFace -> IO ()
freeFontFace (FontFace -> IO ())
-> (GlyphFont -> FontFace) -> GlyphFont -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GlyphFont -> FontFace
gfFace
withGlyphFont :: FilePath -> (GlyphFont -> IO a) -> IO a
withGlyphFont :: forall a. FilePath -> (GlyphFont -> IO a) -> IO a
withGlyphFont FilePath
path = IO GlyphFont -> (GlyphFont -> IO ()) -> (GlyphFont -> IO a) -> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (FilePath -> IO GlyphFont
openGlyphFont FilePath
path) GlyphFont -> IO ()
closeGlyphFont
cachedGlyph :: GlyphFont -> Int -> Char -> IO (Maybe GlyphBitmap)
cachedGlyph :: GlyphFont -> Int -> Char -> IO (Maybe GlyphBitmap)
cachedGlyph GlyphFont
gf Int
size Char
ch = do
cache <- IORef (Map (Int, Char) (Maybe GlyphBitmap))
-> IO (Map (Int, Char) (Maybe GlyphBitmap))
forall a. IORef a -> IO a
readIORef (GlyphFont -> IORef (Map (Int, Char) (Maybe GlyphBitmap))
gfCache GlyphFont
gf)
case Map.lookup (size, ch) cache of
Just Maybe GlyphBitmap
cached -> Maybe GlyphBitmap -> IO (Maybe GlyphBitmap)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe GlyphBitmap
cached
Maybe (Maybe GlyphBitmap)
Nothing -> do
rendered <- FontFace -> Int -> Char -> IO (Maybe GlyphBitmap)
renderGlyph (GlyphFont -> FontFace
gfFace GlyphFont
gf) Int
size Char
ch
modifyIORef' (gfCache gf) (Map.insert (size, ch) rendered)
pure rendered