M Graphics/Layout/CSS/Font.hs => Graphics/Layout/CSS/Font.hs +19 -0
@@ 18,11 18,15 @@ import Graphics.Text.Font.Choose (Pattern(..), Value(..), normalizePattern,
import qualified Data.ByteString as B
import System.IO.Unsafe (unsafePerformIO)
+-- | zero'd `Font'` to serve as the root's parent in a font heirarchy.
placeholderFont = Font' undefined [] (const 0) (const 0) 0 0 0 0 0 0 0 0 1
+-- | Scale-factor for text-shaping APIs.
hbScale :: Font' -> Double
hbScale f = fontSize f*hbUnit
+-- | Magic number informing the value of `hbScale`.
hbUnit = 64 :: Double
+-- | Convert from FontConfig query result to a Harfbuzz font.
pattern2hbfont :: Pattern -> Int -> [Variation] -> Font
pattern2hbfont pat scale variations = createFontWithOptions options face
where
@@ 37,6 41,8 @@ pattern2hbfont pat scale variations = createFontWithOptions options face
value2opt opts ("fontvariations", _:_) = opts {optionVariations = variations}
value2opt opts _ = opts
+-- | Convert Parsed CSS to a `Font'`.
+-- Includes sizing parameters derived from a root & parent `Font'`.
pattern2font :: Pattern -> CSSFont -> Font' -> Font' -> Font'
pattern2font pat styles@CSSFont { cssFontSize = (x,"initial") } parent root =
pattern2font pat styles { cssFontSize = (x*fontSize root," ") } parent root
@@ 73,20 79,32 @@ pattern2font pat styles parent root = Font' {
font' = pattern2hbfont font (round scale') $ variations' fontSize' styles
scale' = fontSize'*hbUnit
+-- | Parsed CSS font properties, excluding the FontConfig query.
data CSSFont = CSSFont {
+ -- | Parsed CSS font-size.
cssFontSize :: Unitted,
+ -- | Parsed CSS line-height.
cssLineheight :: Unitted,
+ -- | Parsed CSS font-variation-settings.
variations :: [Variation],
+ -- | Parsed CSS font-weight.
weightVariation :: Variation,
+ -- | Parsed CSS font-stretch.
widthVariation :: Variation,
+ -- | Parsed CSS font-style.
slantVariation :: Variation,
+ -- | Parsed CSS font-optical-sizing.
opticalSize :: Bool
}
+-- | All font-variations from the parsed CSS properties.
+-- | Requires the resolved font-size in case font-optical-sizing is set.
variations' :: Double -> CSSFont -> [Variation]
variations' fontsize self =
(if opticalSize self then (Variation opsz (realToFrac fontsize):) else id)
(slantVariation self:widthVariation self:weightVariation self:variations self)
+-- | Represents a multiple of the initial font-size.
+-- Resolved by `pattern2font`.
fracDefault :: CSSFont -> Double -> Maybe CSSFont
fracDefault self frac = Just self {
cssFontSize = (frac,"initial")
@@ 194,6 212,7 @@ instance PropertyParser CSSFont where
longhand _ _ _ _ = Nothing
+-- | Utility for parsing multiple font variations (via Harfbuzz).
parseVariations (x@(String _):y@(Number _ _):Comma:toks)
| Just var <- parseVariation $ Txt.unpack $ serialize [x, y],
Just vars <- parseVariations toks = Just $ var:vars
M Graphics/Layout/CSS/Length.hs => Graphics/Layout/CSS/Length.hs +26 -0
@@ 11,10 11,15 @@ import Graphics.Text.Font.Choose (Pattern(..))
import Graphics.Layout.Box
+-- | A number+unit, prior to resolving side units.
+-- The unit may alternately represent a keyword, in which case the number is
+-- ignored & typically set to 0.
type Unitted = (Double, Txt.Text)
+-- | The CSS `auto` keyword.
auto :: Unitted
auto = (0,"auto")
+-- | Parse a pre-tokenized CSS length value.
parseLength :: [Token] -> Maybe Unitted
parseLength [Percentage _ x] = Just (n2f x,"%")
parseLength [Dimension _ x unit]
@@ 23,15 28,20 @@ parseLength [Dimension _ x unit]
parseLength [Ident "auto"] = Just (0,"auto")
parseLength [Ident "initial"] = Just (0,"auto")
parseLength _ = Nothing
+-- | Variant of `parseLength` which supports min-content & max-content keywords.
parseLength' [Ident "min-content"] = Just (0,"min-content")
parseLength' [Ident "max-content"] = Just (0,"max-content")
parseLength' toks = parseLength toks
+-- | Supported length units.
units = Txt.words "cap ch em ex ic lh rem rlh vh vw vmax vmin px cm mm Q in pc pt %"
+-- | Convert a lexed number to a Double.
+n2f :: (Fractional x, RealFloat x) => NumericValue -> x
n2f (NVInteger x) = realToFrac x
n2f (NVNumber x) = toRealFloat x
+-- | Resolve a parsed length according to the sizing parameters in a given `Font'`.
finalizeLength :: Unitted -> Font' -> Length
finalizeLength (x,"cap") f = Pixels $ x*fontHeight f 'A'
finalizeLength (x,"ch") f = Pixels $ x*fontAdvance f '0'
@@ 59,20 69,36 @@ finalizeLength (_,"min-content") _ = Min
finalizeLength (_,"max-content") _ = Preferred
finalizeLength (x, " ") _ = Pixels x -- Internal constant value...
finalizeLength (_,unit) _ = trace ("Invalid unit " ++ Txt.unpack unit) $ Pixels 0
+-- | Convert from a computed length to the "pt" unit.
px2pt f x = x / scale f / 96 * 72
+-- | A Harfbuzz font with sizing parameters.
data Font' = Font' {
+ -- | The Harfbuzz font used to shape text & query character-size information.
hbFont :: Font,
+ -- | The FontConfig query result. Useful to incorporate into output rendering.
pattern :: Pattern,
+ -- | Query the height of a character.
+ -- Used for cap, ex, or ic units.
fontHeight :: Char -> Double,
+ -- | Query the width of a character, used for ch unit.
fontAdvance :: Char -> Double,
+ -- | The desired font-size, used for em unit.
fontSize :: Double,
+ -- | The root font's size, used for rem unit.
rootEm :: Double,
+ -- | The desired line-height, used for lh unit.
lineheight :: Double,
+ -- | The root font's line-height, used for rlh unit.
rlh :: Double,
+ -- | Scale-factor for vh unit.
vh :: Double,
+ -- | Scale-factor for vw unit.
vw :: Double,
+ -- | Scale-factor for vmax unit.
vmax :: Double,
+ -- | Scale-factor for vmin unit.
vmin :: Double,
+ -- | How many device pixels in a CSS px?
scale :: Double
}
M Graphics/Layout/Inline.hs => Graphics/Layout/Inline.hs +1 -1
@@ 22,7 22,7 @@ inlineMinWidth :: Font' -> Paragraph -> Double
inlineMinWidth font self = hbScale' font $ width $ layoutPlain' self 0
inlineMin :: (CastDouble x, CastDouble y) => Font' -> Paragraph -> Size x y
inlineMin font self = Size (c font $ width rect) (c font $ height rect)
- where rect = layoutPlain' self 0
+ where rect = layoutPlain' self 0
inlineNatWidth :: Font' -> Paragraph -> Double
inlineNatWidth font self = hbScale' font $ width $ layoutPlain' self maxBound
inlineHeight :: Font' -> Double -> Paragraph -> Double