From 0b5dc6256172f8eb29fe15fddba2f7860a475504 Mon Sep 17 00:00:00 2001 From: Adrian Cochrane Date: Tue, 20 Dec 2022 10:43:32 +1300 Subject: [PATCH] Document FreeType integration. --- FreeType/FontConfig.hs | 55 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/FreeType/FontConfig.hs b/FreeType/FontConfig.hs index 3240eef..0809702 100644 --- a/FreeType/FontConfig.hs +++ b/FreeType/FontConfig.hs @@ -35,16 +35,27 @@ import FreeType.Exception (FtError(..)) c2w :: Char -> Word32 c2w = fromIntegral . fromEnum +-- | Maps a Unicode char to a glyph index. +-- This function uses information from several possible underlying encoding +-- tables to work around broken fonts. As a result, this function isn't designed +-- to be used in performance sensitive areas; results from this function are +-- intended to be cached by higher level functions. ftCharIndex :: FT_Face -> Char -> Word ftCharIndex face = fcFreeTypeCharIndex face . c2w foreign import ccall "FcFreeTypeCharIndex" fcFreeTypeCharIndex :: FT_Face -> Word32 -> Word +-- | Scans a FreeType face and returns the set of encoded Unicode chars. ftCharSet :: FT_Face -> CharSet ftCharSet face = unsafePerformIO $ thawCharSet_ $ fcFreeTypeCharSet face nullPtr foreign import ccall "FcFreeTypeCharSet" fcFreeTypeCharSet :: FT_Face -> Ptr () -> IO CharSet_ -- 2nd arg's deprecated! -data Spacing = Proportional | Dual | Mono +-- | How consistant are the widths of the chars in a font. +data Spacing = Proportional -- ^ Where the font has glyphs of many widths. + | Dual -- ^ Where the font has glyphs in precisely two widths. + | Mono -- ^ Where all glyphs have the same width. +-- | Scans a FreeType face and returns the set of encoded Unicode chars. +-- `snd` receives the computed spacing type of the font. ftCharSetAndSpacing :: FT_Face -> (CharSet, Spacing) ftCharSetAndSpacing face = unsafePerformIO $ alloca $ \spacing' -> do chars <- thawCharSet_ $ fcFreeTypeCharSetAndSpacing face nullPtr spacing' @@ -58,6 +69,8 @@ ftCharSetAndSpacing face = unsafePerformIO $ alloca $ \spacing' -> do foreign import ccall "FcFreeTypeCharSetAndSpacing" fcFreeTypeCharSetAndSpacing :: FT_Face -> Ptr () -> Ptr Int -> IO CharSet_ -- 2nd arg's deprecated! +-- | Constructs a pattern representing the 'id'th face in 'fst'. +-- The number of faces in 'file' is returned in 'snd'. ftQuery :: FilePath -> Int -> IO (Pattern, Int) ftQuery filename id = withCString filename $ \filename' -> alloca $ \count' -> do pattern <- thawPattern_ $ fcFreeTypeQuery filename' id nullPtr count' @@ -66,6 +79,10 @@ ftQuery filename id = withCString filename $ \filename' -> alloca $ \count' -> d foreign import ccall "FcFreeTypeQuery" fcFreeTypeQuery :: CString -> Int -> Ptr () -> Ptr Int -> IO Pattern_ -- 3rd arg's deprecated! +-- | Constructs patterns found in 'filename'. +-- If id is -1, then all patterns found in 'filename' are added to 'fst'. +-- Otherwise, this function works exactly like `ftQuery`. +-- The number of faces in 'filename' is returned in 'snd'. ftQueryAll :: FilePath -> Int -> IO (FontSet, Int) ftQueryAll filename id = withCString filename $ \filename' -> alloca $ \count' -> withFontSet [] $ \fonts' -> do @@ -76,6 +93,8 @@ ftQueryAll filename id = withCString filename $ \filename' -> alloca $ \count' - foreign import ccall "FcFreeTypeQueryAll" fcFreeTypeQueryAll :: CString -> Int -> Ptr () -> Ptr Int -> FontSet_ -> IO Word -- 2nd arg's deprecated! +-- | Constructs a pattern representing 'face'. +-- 'filename' and 'id' are used solely as data for pattern elements. ftQueryFace :: FT_Face -> FilePath -> Int -> IO Pattern ftQueryFace face filename id = withCString filename $ \filename' -> thawPattern_ $ fcFreeTypeQueryFace face filename' id nullPtr @@ -88,8 +107,9 @@ foreign import ccall "FcFreeTypeQueryFace" fcFreeTypeQueryFace :: --- Untested ------ +-- | A `FT_Face` queried from FontConfig with glyph-loading parameters. data FTFC_Instance = Instance { - fontName :: String, + fontName :: Maybe String, fontPath :: Maybe String, fontFace :: FT_Face, fontLoadFlags :: Int, @@ -105,18 +125,27 @@ data FTFC_Instance = Instance { fontFeats :: [String], -- Callers probably want to validate via harfbuzz fontMetrics :: FTFC_Metrics } +-- | Results queried from FontConfig with caller-relevant properties, +-- notably relating to layout. data FTFC_Metrics = Metrics { height :: Int, descent :: Int, ascent :: Int, - maxAdvance :: (Int, Int), + maxAdvance :: (Int, Int), -- Width/height of font's widest glyph. metricsAntialias :: Bool, metricsSubpixel :: FTFC_Subpixel, - metricsName :: String + metricsName :: Maybe String } -data FTFC_Subpixel = SubpixelNone | SubpixelHorizontalRGB | SubpixelHorizontalBGR | - SubpixelVerticalRGB | SubpixelVerticalBGR | SubpixelDefault - +-- | Defines subpixel order to use. +-- Note that this is *ignored* if antialiasing has been disabled. +data FTFC_Subpixel = SubpixelNone -- ^ From FontConfig. + | SubpixelHorizontalRGB | SubpixelHorizontalBGR | + SubpixelVerticalRGB | SubpixelVerticalBGR + | SubpixelDefault -- ^ Disable subpixel antialiasing. + +-- | Converts the results of a FontConfig query requesting a specific size +-- into a `FT_Face` & related properties. +-- Throw exceptions. instantiatePattern :: FT_Library -> Pattern -> (Double, Double) -> IO FTFC_Instance instantiatePattern ftlib pattern (req_pt_size, req_px_size) = do let dpi = fromMaybe 75 $ getValue' "dpi" pattern :: Double @@ -181,7 +210,7 @@ instantiatePattern ftlib pattern (req_pt_size, req_px_size) = do let metrics' = srMetrics size' let c x = fromIntegral x / 64 * pixel_fixup return Instance { - fontName = getValue0 "fullname" pattern, + fontName = getValue' "fullname" pattern, fontPath = getValue' "file" pattern, fontFace = ft_face, fontLoadFlags = load_target .|. load_flags .|. ft_LOAD_COLOR, @@ -209,17 +238,23 @@ instantiatePattern ftlib pattern (req_pt_size, req_px_size) = do 3 -> SubpixelVerticalRGB 4 -> SubpixelVerticalBGR _ -> SubpixelNone, - metricsName = getValue0 "fullname" pattern + metricsName = getValue' "fullname" pattern } } +-- | Results from `glyphForIndex`. data FTFC_Glyph a = Glyph { - glyphFontName :: String, + glyphFontName :: Maybe String, glyphImage :: a, glyphAdvance :: (Double, Double), glyphSubpixel :: FTFC_Subpixel } +-- | Looks up a given glyph in a `FTFC_Instance` & its underlying `FT_Face` +-- Taking into account additional properties from FontConfig. +-- Runs a provided callback to render the glyph into a reusable datastructure. +-- The `FT_Bitmap` given to this callback must not be used outside it. +-- Throws exceptions. glyphForIndex :: FTFC_Instance -> Word32 -> FTFC_Subpixel -> (FT_Bitmap -> IO a) -> IO (FTFC_Glyph a) glyphForIndex font index subpixel cb = do -- 2.30.2