~alcinnz/fontconfig-pure

fontconfig-pure/Graphics/Text/Font/Choose/LangSet.hs -rw-r--r-- 4.8 KiB
dfb515ef — Adrian Cochrane Segfault fixes. 1 year, 2 months ago
                                                                                
7b41b9f8 Adrian Cochrane
e21707cb Adrian Cochrane
7b41b9f8 Adrian Cochrane
e21707cb Adrian Cochrane
7b41b9f8 Adrian Cochrane
e21707cb Adrian Cochrane
7b41b9f8 Adrian Cochrane
e21707cb Adrian Cochrane
d87a046b Adrian Cochrane
e21707cb Adrian Cochrane
d87a046b Adrian Cochrane
e21707cb Adrian Cochrane
d87a046b Adrian Cochrane
e21707cb Adrian Cochrane
7b41b9f8 Adrian Cochrane
e21707cb Adrian Cochrane
5df07b35 Adrian Cochrane
7b41b9f8 Adrian Cochrane
d87a046b Adrian Cochrane
64bcb432 Adrian Cochrane
d87a046b Adrian Cochrane
7b41b9f8 Adrian Cochrane
d87a046b Adrian Cochrane
7b41b9f8 Adrian Cochrane
d87a046b Adrian Cochrane
e21707cb Adrian Cochrane
7b41b9f8 Adrian Cochrane
e21707cb Adrian Cochrane
7b41b9f8 Adrian Cochrane
e21707cb Adrian Cochrane
d87a046b Adrian Cochrane
e21707cb Adrian Cochrane
7b41b9f8 Adrian Cochrane
e21707cb Adrian Cochrane
7b41b9f8 Adrian Cochrane
e21707cb Adrian Cochrane
7b41b9f8 Adrian Cochrane
e21707cb Adrian Cochrane
24a77a5f Adrian Cochrane
e21707cb Adrian Cochrane
7b41b9f8 Adrian Cochrane
e21707cb Adrian Cochrane
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
module Graphics.Text.Font.Choose.LangSet (LangSet, defaultLangs, langs,
    langSetCompare, langNormalize, langCharSet,
    LangSet_, withLangSet, thawLangSet) where

import Data.Set (Set)
import qualified Data.Set as Set
import Graphics.Text.Font.Choose.Strings (thawStrSet, thawStrSet_, StrSet_)
import Graphics.Text.Font.Choose.CharSet (thawCharSet, CharSet_, CharSet)
import Graphics.Text.Font.Choose.Result (throwNull, throwFalse)

import Foreign.Ptr (Ptr)
import Foreign.C.String (CString, withCString, peekCString)
import Foreign.Marshal.Alloc (free)
import Control.Exception (bracket)
import Control.Monad (forM)
import System.IO.Unsafe (unsafePerformIO)

-- | An `LangSet` is a set of language names (each of which include language and
-- an optional territory). They are used when selecting fonts to indicate which
-- languages the fonts need to support. Each font is marked, using language
-- orthography information built into fontconfig, with the set of supported languages.
type LangSet = Set String

-- | Returns a string set of the default languages according to the environment
-- variables on the system. This function looks for them in order of FC_LANG,
-- LC_ALL, LC_CTYPE and LANG then. If there are no valid values in those
-- environment variables, "en" will be set as fallback.
defaultLangs :: IO LangSet
defaultLangs = thawStrSet =<< fcGetDefaultLangs
foreign import ccall "FcGetDefaultLangs" fcGetDefaultLangs :: IO StrSet_

-- | Returns a string set of all known languages.
langs :: LangSet
langs = unsafePerformIO $ thawStrSet_ $ fcGetLangs
foreign import ccall "FcGetLangs" fcGetLangs :: IO StrSet_

-- | Result of language comparisons.
data LangResult = SameLang | DifferentTerritory | DifferentLang
    deriving (Enum, Eq, Read, Show)
-- | `langSetCompare` compares language coverage for ls_a and ls_b.
-- If they share any language and territory pair, returns `SameLang`.
-- If they share a language but differ in which territory that language is for,
-- this function returns `DifferentTerritory`.
-- If they share no languages in common, this function returns `DifferentLang`.
langSetCompare :: LangSet -> LangSet -> LangResult
langSetCompare a b = unsafePerformIO $ withLangSet a $ \a' -> withLangSet b $ \b' ->
    (toEnum <$> fcLangSetCompare a' b')
foreign import ccall "FcLangSetCompare" fcLangSetCompare ::
    LangSet_ -> LangSet_ -> IO Int

-- | `langSetContains` returns FcTrue if ls_a contains every language in ls_b.
-- ls_a will 'contain' a language from ls_b if ls_a has exactly the language,
-- or either the language or ls_a has no territory.
langSetContains :: LangSet -> LangSet -> Bool
langSetContains a b = unsafePerformIO $ withLangSet a $ \a' -> withLangSet b $
    fcLangSetContains a'
foreign import ccall "FcLangSetContains" fcLangSetContains ::
    LangSet_ -> LangSet_ -> IO Bool

-- | FcLangSetHasLang checks whether ls supports lang.
-- If ls has a matching language and territory pair, this function returns
-- `SameLang`. If ls has a matching language but differs in which territory
-- that language is for, this function returns `DifferentTerritory`. If ls has
-- no matching language, this function returns `DifferentLang`.
langSetHasLang :: LangSet -> String -> LangResult
langSetHasLang a b = unsafePerformIO $ withLangSet a $ \a' -> withCString b $ \b' ->
    (toEnum <$> fcLangSetHasLang a' b')
foreign import ccall "FcLangSetHasLang" fcLangSetHasLang :: LangSet_ -> CString -> IO Int

-- | Returns a string to make lang suitable on FontConfig.
langNormalize :: String -> String
langNormalize "" = ""
langNormalize lang = unsafePerformIO $ withCString lang (peekCString_ . fcLangNormalize)
foreign import ccall "FcLangNormalize" fcLangNormalize :: CString -> CString
peekCString_ str' = do
    str <- peekCString $ throwNull str'
    free str'
    return str

-- | Returns the FcCharMap for a language.
langCharSet :: String -> CharSet
langCharSet lang = unsafePerformIO $
    withCString lang (thawCharSet . throwNull . fcLangGetCharSet)
foreign import ccall "FcLangGetCharSet" fcLangGetCharSet :: CString -> CharSet_

------
--- Low-level
------

data LangSet'
type LangSet_ = Ptr LangSet'

withNewLangSet :: (LangSet_ -> IO a) -> IO a
withNewLangSet = bracket (throwNull <$> fcLangSetCreate) fcLangSetDestroy
foreign import ccall "FcLangSetCreate" fcLangSetCreate :: IO LangSet_
foreign import ccall "FcLangSetDestroy" fcLangSetDestroy :: LangSet_ -> IO ()

withLangSet :: LangSet -> (LangSet_ -> IO a) -> IO a
withLangSet langs cb = withNewLangSet $ \langs' -> do
    forM (Set.elems langs) $ flip withCString $ \lang' ->
        throwFalse <$> fcLangSetAdd langs' lang'
    cb langs'
foreign import ccall "FcLangSetAdd" fcLangSetAdd :: LangSet_ -> CString -> IO Bool

thawLangSet :: LangSet_ -> IO LangSet
thawLangSet = thawStrSet_ . fcLangSetGetLangs
foreign import ccall "FcLangSetGetLangs" fcLangSetGetLangs :: LangSet_ -> IO StrSet_