~alcinnz/fontconfig-pure

0b5dc6256172f8eb29fe15fddba2f7860a475504 — Adrian Cochrane 2 years ago ce6932f
Document FreeType integration.
1 files changed, 45 insertions(+), 10 deletions(-)

M FreeType/FontConfig.hs
M FreeType/FontConfig.hs => FreeType/FontConfig.hs +45 -10
@@ 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