@@ 28,7 28,15 @@ import Linear
import Typograffiti.Atlas
import Typograffiti.Cache
import Typograffiti.Glyph
-import Typograffiti.Utils (FT_Face, FT_GlyphSlot, FreeTypeIO(..))
+
+-- For font registration APIs
+import Typograffiti.Utils
+import FreeType.Support.Bitmap.Internal
+import FreeType.Support.Outline.Internal
+import FreeType.Support.Outline
+import FreeType.Core.Types
+import Data.Maybe (fromMaybe)
+import System.IO
-- | A pre-rendered bit of text, ready to display given
@@ 187,3 195,58 @@ registerFont store key fce sz cb = do
$ putTMVar mvar
$ s{ textRenderingDataFontMap = M.insert (key, sz') font fontmap }
return font
+
+registerStyledFont
+ :: ( MonadIO m
+ , MonadError TypograffitiError m
+ , Layout t
+ )
+ => FontStore t
+ -> String
+ -- ^ Key by which to identify this styled font
+ -> FilePath
+ -- ^ Path to the raw fontfile
+ -> FT_Pos
+ -- ^ How much to embolden the font
+ -- Negative values lighten the font.
+ -> Maybe FT_Pos
+ -- ^ How much to embolden the font vertically, if different from horizontally.
+ -> FT_Fixed
+ -- ^ How much to slant the font, approximating italics.
+ -> GlyphSize
+ -- ^ The desired fontsize
+ -> m (Font t)
+-- | Registers font under the given key modified to approximate the desired boldness & obliqueness.
+-- Adds negligable CPU latency,
+-- but best results always come from giving the font designing full artistic control.
+-- Obliqueness isn't currently supported on bitmap fonts.
+registerStyledFont store key file weight vweight slant sz = do
+ e <- liftIO $ runFreeType $ do
+ lib <- getLibrary
+ fce <- newFace file
+ registerFont store key fce (Just sz) $ modifyGlyph lib
+
+ either
+ (throwError . TypograffitiErrorFreetype "cannot alloc atlas")
+ (return . fst)
+ e
+ where
+ modifyGlyph lib glyf = do
+ glyf' <- liftIO $ peek glyf
+ case gsrFormat glyf' of
+ FT_GLYPH_FORMAT_OUTLINE -> modifyOutline glyf
+ FT_GLYPH_FORMAT_BITMAP -> modifyBitmap lib glyf
+ x -> liftIO $ do
+ hPrint stderr "Unsupported glyph format:"
+ hPrint stderr x
+ modifyOutline glyf = do
+ let outline = gsrOutline' glyf
+ runIOErr "ft_Outline_EmboldenXY" $
+ ft_Outline_EmboldenXY' outline weight $ fromMaybe weight vweight
+ liftIO $ ft_Outline_Transform outline $ FT_Matrix 1 slant 0 1
+ renderGlyph glyf
+ modifyBitmap lib glyf = do
+ let bitmap = gsrBitmap' glyf
+ runIOErr "ft_Bitmap_Embolden" $
+ ft_Bitmap_Embolden' lib bitmap weight $ fromMaybe weight vweight
+ -- FreeType doesn't have a transform method on bitmaps.
@@ 4,6 4,7 @@ module Typograffiti.Utils (
module FT
, FreeTypeT
, FreeTypeIO
+ , runIOErr
, getAdvance
, getCharIndex
, getLibrary
@@ 23,6 24,8 @@ module Typograffiti.Utils (
, ft_LOAD_FORCE_AUTOHINT, ft_LOAD_CROP_BITMAP, ft_LOAD_PEDANTIC, ft_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
, ft_LOAD_NO_RECURSE, ft_LOAD_IGNORE_TRANSFORM, ft_LOAD_MONOCHROME, ft_LOAD_LINEAR_DESIGN
, ft_LOAD_NO_AUTOHINT, ft_LOAD_COLOR, ft_LOAD_COMPUTE_METRICS, ft_LOAD_BITMAP_METRICS_ONLY
+ , gsrOutline'
+ , gsrBitmap'
) where
import Control.Monad.IO.Class (MonadIO, liftIO)
@@ 32,9 35,11 @@ import Control.Monad (unless)
import FreeType.Core.Base as FT
import FreeType.Core.Base.Internal as FT
import FreeType.Core.Types as FT
+import FreeType.Support.Outline as FT
import Foreign as FT
import Foreign.C.String as FT
import Unsafe.Coerce
+import Foreign.Ptr (Ptr(..), plusPtr)
-- TODO: Tease out the correct way to handle errors.
-- They're kinda thrown all willy nilly.
@@ 164,3 169,10 @@ getAdvance slot = do
slot' <- liftIO $ peek slot
let FT_Vector vx vy = gsrAdvance slot'
return (fromIntegral vx, fromIntegral vy)
+
+-- Offsets taken from: https://hackage.haskell.org/package/freetype2-0.2.0/docs/src/FreeType.Circular.Types.html#line-372
+gsrOutline' :: FT_GlyphSlot -> Ptr FT_Outline
+gsrOutline' slot = plusPtr slot 200
+
+gsrBitmap' :: FT_GlyphSlot -> Ptr FT_Bitmap
+gsrBitmap' slot = plusPtr slot 152