~alcinnz/CatTrap

93c6516bd685ea45627cd62abfd2241d91711553 — Adrian Cochrane 1 year, 8 months ago 9b179cc
Commence reference documentation!
3 files changed, 46 insertions(+), 1 deletions(-)

M Graphics/Layout/CSS/Font.hs
M Graphics/Layout/CSS/Length.hs
M Graphics/Layout/Inline.hs
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