minitypeset-opengl 0.2.0.1 → 0.3.0.0
raw patch · 10 files changed
+888/−117 lines, 10 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Graphics.Rendering.MiniTypeset.Document: Angle :: Bracket
- Graphics.Rendering.MiniTypeset.Document: AngleQuote :: Bracket
- Graphics.Rendering.MiniTypeset.Document: Bottom :: Bracket
- Graphics.Rendering.MiniTypeset.Document: Brace :: Bracket
- Graphics.Rendering.MiniTypeset.Document: Ceil :: Bracket
- Graphics.Rendering.MiniTypeset.Document: Floor :: Bracket
- Graphics.Rendering.MiniTypeset.Document: FrenchQuote :: Bracket
- Graphics.Rendering.MiniTypeset.Document: Paren :: Bracket
- Graphics.Rendering.MiniTypeset.Document: Square :: Bracket
- Graphics.Rendering.MiniTypeset.Document: Top :: Bracket
- Graphics.Rendering.MiniTypeset.Document: bracketChars :: Bracket -> (Char, Char)
- Graphics.Rendering.MiniTypeset.Document: data Bracket
- Graphics.Rendering.MiniTypeset.Document: instance GHC.Classes.Eq Graphics.Rendering.MiniTypeset.Document.Bracket
- Graphics.Rendering.MiniTypeset.Document: instance GHC.Classes.Ord Graphics.Rendering.MiniTypeset.Document.Bracket
- Graphics.Rendering.MiniTypeset.Document: instance GHC.Show.Show Graphics.Rendering.MiniTypeset.Document.Bracket
- Graphics.Rendering.MiniTypeset.Layout: SizeIndex :: Int -> SizeIndex
- Graphics.Rendering.MiniTypeset.Layout: calculateSizeHeight :: Height -> SizeIndex -> Int
- Graphics.Rendering.MiniTypeset.Layout: newtype SizeIndex
- Graphics.Rendering.MiniTypeset.Layout: succSizeIndex :: SizeIndex -> SizeIndex
+ Graphics.Rendering.MiniTypeset: Angle :: Delimiter
+ Graphics.Rendering.MiniTypeset: AngleQuote :: Delimiter
+ Graphics.Rendering.MiniTypeset: Bottom :: Delimiter
+ Graphics.Rendering.MiniTypeset: Brace :: Delimiter
+ Graphics.Rendering.MiniTypeset: Ceil :: Delimiter
+ Graphics.Rendering.MiniTypeset: Floor :: Delimiter
+ Graphics.Rendering.MiniTypeset: Guillemet :: Delimiter
+ Graphics.Rendering.MiniTypeset: LeftDelim :: WhichDelim
+ Graphics.Rendering.MiniTypeset: Paren :: Delimiter
+ Graphics.Rendering.MiniTypeset: RightDelim :: WhichDelim
+ Graphics.Rendering.MiniTypeset: Square :: Delimiter
+ Graphics.Rendering.MiniTypeset: Top :: Delimiter
+ Graphics.Rendering.MiniTypeset: Tortoise :: Delimiter
+ Graphics.Rendering.MiniTypeset: VertDouble :: Delimiter
+ Graphics.Rendering.MiniTypeset: VertSingle :: Delimiter
+ Graphics.Rendering.MiniTypeset: data Delimiter
+ Graphics.Rendering.MiniTypeset: data WhichDelim
+ Graphics.Rendering.MiniTypeset: delimiterChars :: Delimiter -> (Char, Char)
+ Graphics.Rendering.MiniTypeset.Box: absboxSelectQuad :: WhichQuad -> AbsBox -> Quad
+ Graphics.Rendering.MiniTypeset.Box: boxInnerHeight :: Box -> Double
+ Graphics.Rendering.MiniTypeset.Box: boxInnerWidth :: Box -> Double
+ Graphics.Rendering.MiniTypeset.Box: boxSelectQuad :: WhichQuad -> Box -> Quad
+ Graphics.Rendering.MiniTypeset.Box: delimiterBox :: (Box, Box, Box) -> [Box] -> (Box, [Pos])
+ Graphics.Rendering.MiniTypeset.Box: evens :: [a] -> [a]
+ Graphics.Rendering.MiniTypeset.Box: fractionBox :: Double -> Box -> Box -> (Box, (Pos, Pos))
+ Graphics.Rendering.MiniTypeset.Box: interleave :: [a] -> [a] -> [a]
+ Graphics.Rendering.MiniTypeset.Box: odds :: [a] -> [a]
+ Graphics.Rendering.MiniTypeset.Box: quadsLUB :: [Quad] -> Quad
+ Graphics.Rendering.MiniTypeset.Box: shiftBox :: Pos -> Box -> Box
+ Graphics.Rendering.MiniTypeset.Box: trimBox :: Box -> Box
+ Graphics.Rendering.MiniTypeset.Common: Angle :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: AngleQuote :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: Bottom :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: Brace :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: Ceil :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: Floor :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: Guillemet :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: LeftDelim :: WhichDelim
+ Graphics.Rendering.MiniTypeset.Common: Paren :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: RightDelim :: WhichDelim
+ Graphics.Rendering.MiniTypeset.Common: Square :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: Top :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: Tortoise :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: VertDouble :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: VertSingle :: Delimiter
+ Graphics.Rendering.MiniTypeset.Common: data Delimiter
+ Graphics.Rendering.MiniTypeset.Common: data WhichDelim
+ Graphics.Rendering.MiniTypeset.Common: delimiterChars :: Delimiter -> (Char, Char)
+ Graphics.Rendering.MiniTypeset.Common: instance GHC.Classes.Eq Graphics.Rendering.MiniTypeset.Common.Delimiter
+ Graphics.Rendering.MiniTypeset.Common: instance GHC.Classes.Eq Graphics.Rendering.MiniTypeset.Common.WhichDelim
+ Graphics.Rendering.MiniTypeset.Common: instance GHC.Classes.Ord Graphics.Rendering.MiniTypeset.Common.Delimiter
+ Graphics.Rendering.MiniTypeset.Common: instance GHC.Classes.Ord Graphics.Rendering.MiniTypeset.Common.WhichDelim
+ Graphics.Rendering.MiniTypeset.Common: instance GHC.Show.Show Graphics.Rendering.MiniTypeset.Common.Delimiter
+ Graphics.Rendering.MiniTypeset.Common: instance GHC.Show.Show Graphics.Rendering.MiniTypeset.Common.WhichDelim
+ Graphics.Rendering.MiniTypeset.Delimiters: Adjustable :: (forall a. Double -> Document a) -> CompoundDelim
+ Graphics.Rendering.MiniTypeset.Delimiters: FixDelim :: (forall a. Document a) -> CompoundDelim
+ Graphics.Rendering.MiniTypeset.Delimiters: FixedDelim :: !(Char, Char) -> DelimImpl
+ Graphics.Rendering.MiniTypeset.Delimiters: GrowingDelim :: (forall a. DelimGrower a) -> DelimImpl
+ Graphics.Rendering.MiniTypeset.Delimiters: botNegMargin :: Double -> Document a -> Document a
+ Graphics.Rendering.MiniTypeset.Delimiters: braceSection1 :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: braceSection2 :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: buildBrace :: DelimBuilder
+ Graphics.Rendering.MiniTypeset.Delimiters: buildBracket :: DelimBuilder
+ Graphics.Rendering.MiniTypeset.Delimiters: buildDblVertical :: DelimBuilder
+ Graphics.Rendering.MiniTypeset.Delimiters: buildParen :: DelimBuilder
+ Graphics.Rendering.MiniTypeset.Delimiters: buildVertical :: DelimBuilder
+ Graphics.Rendering.MiniTypeset.Delimiters: data CompoundDelim
+ Graphics.Rendering.MiniTypeset.Delimiters: data DelimImpl
+ Graphics.Rendering.MiniTypeset.Delimiters: delimHMargin :: Double
+ Graphics.Rendering.MiniTypeset.Delimiters: delimHangAbove :: Double
+ Graphics.Rendering.MiniTypeset.Delimiters: delimHangBelow :: Double
+ Graphics.Rendering.MiniTypeset.Delimiters: delimVMargin :: Double
+ Graphics.Rendering.MiniTypeset.Delimiters: delimiterImpl :: Delimiter -> DelimImpl
+ Graphics.Rendering.MiniTypeset.Delimiters: fdivmod :: Double -> Double -> (Int, Double)
+ Graphics.Rendering.MiniTypeset.Delimiters: finalDelim :: Height -> Delimiter -> Double -> WhichDelim -> Document a
+ Graphics.Rendering.MiniTypeset.Delimiters: finalDelim' :: Double -> Height -> Delimiter -> Double -> WhichDelim -> Document a
+ Graphics.Rendering.MiniTypeset.Delimiters: growBrace :: Height -> WhichDelim -> Double -> Document a
+ Graphics.Rendering.MiniTypeset.Delimiters: growBracket :: Height -> WhichDelim -> Double -> Document a
+ Graphics.Rendering.MiniTypeset.Delimiters: growDblVertical :: Height -> WhichDelim -> Double -> Document a
+ Graphics.Rendering.MiniTypeset.Delimiters: growParen :: Height -> WhichDelim -> Double -> Document a
+ Graphics.Rendering.MiniTypeset.Delimiters: growVertical :: Height -> WhichDelim -> Double -> Document a
+ Graphics.Rendering.MiniTypeset.Delimiters: intBot :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: intExt :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: intTop :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: lbraceBot :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: lbraceMid :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: lbraceTop :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: lbracketBot :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: lbracketExt :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: lbracketTop :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: lparenBot :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: lparenExt :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: lparenTop :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: lrBraceExt :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: rbraceBot :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: rbraceMid :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: rbraceTop :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: rbracketBot :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: rbracketExt :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: rbracketTop :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: rescale :: (Double, Double) -> Double -> Double
+ Graphics.Rendering.MiniTypeset.Delimiters: rescaleTo :: (Double, Double) -> (Double, Double) -> Double -> Double
+ Graphics.Rendering.MiniTypeset.Delimiters: rparenBot :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: rparenExt :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: rparenTop :: Char
+ Graphics.Rendering.MiniTypeset.Delimiters: sizedCompoundDelim :: CompoundDelim -> Double -> Document a
+ Graphics.Rendering.MiniTypeset.Delimiters: symmNegMargin :: Double -> Document a -> Document a
+ Graphics.Rendering.MiniTypeset.Delimiters: topNegMargin :: Double -> Document a -> Document a
+ Graphics.Rendering.MiniTypeset.Delimiters: type CompoundLevel = Int
+ Graphics.Rendering.MiniTypeset.Delimiters: type DelimBuilder = Height -> CompoundLevel -> WhichDelim -> CompoundDelim
+ Graphics.Rendering.MiniTypeset.Delimiters: type DelimGrower a = Height -> WhichDelim -> Double -> Document a
+ Graphics.Rendering.MiniTypeset.Document: Delimited :: !Delimiter -> [Document ident] -> Document ident
+ Graphics.Rendering.MiniTypeset.Document: Fraction :: !Bool -> !Document ident -> !Document ident -> Document ident
+ Graphics.Rendering.MiniTypeset.Document: RePosition :: !Pos -> !Document ident -> Document ident
+ Graphics.Rendering.MiniTypeset.Document: Trim :: !Document ident -> Document ident
+ Graphics.Rendering.MiniTypeset.Document: UnsafeResize :: !(Double, Double) -> !Document ident -> Document ident
+ Graphics.Rendering.MiniTypeset.Document: choose :: Document a -> Document a -> Document a
+ Graphics.Rendering.MiniTypeset.Document: choose' :: Delimiter -> Document a -> Document a -> Document a
+ Graphics.Rendering.MiniTypeset.Document: delimited :: Delimiter -> Document a -> Document a
+ Graphics.Rendering.MiniTypeset.Document: delimiteds :: Delimiter -> [Document a] -> Document a
+ Graphics.Rendering.MiniTypeset.Document: fraction :: Document a -> Document a -> Document a
+ Graphics.Rendering.MiniTypeset.Layout: CustomSize :: !(Double, Double) -> !SizeIndex -> SizeIndex
+ Graphics.Rendering.MiniTypeset.Layout: FractionSize :: SizeIndex
+ Graphics.Rendering.MiniTypeset.Layout: NormalSize :: SizeIndex
+ Graphics.Rendering.MiniTypeset.Layout: ScriptSize1 :: SizeIndex
+ Graphics.Rendering.MiniTypeset.Layout: ScriptSize2 :: SizeIndex
+ Graphics.Rendering.MiniTypeset.Layout: ScriptSize3 :: SizeIndex
+ Graphics.Rendering.MiniTypeset.Layout: [_hlineWhichQuad] :: LayoutDecoration -> !WhichQuad
+ Graphics.Rendering.MiniTypeset.Layout: calculateSizeXHeight :: Height -> SizeIndex -> Int
+ Graphics.Rendering.MiniTypeset.Layout: calculateSizeYHeight :: Height -> SizeIndex -> Int
+ Graphics.Rendering.MiniTypeset.Layout: data SizeIndex
+ Graphics.Rendering.MiniTypeset.Layout: fracLinePos :: Double
+ Graphics.Rendering.MiniTypeset.Layout: fracSuccSizeIndex :: SizeIndex -> SizeIndex
+ Graphics.Rendering.MiniTypeset.Layout: fracYMargin :: Double
+ Graphics.Rendering.MiniTypeset.Layout: fractionSize :: Double
+ Graphics.Rendering.MiniTypeset.Layout: scriptSuccSizeIndex :: SizeIndex -> SizeIndex
+ Graphics.Rendering.MiniTypeset.MultiFont: encodeXYHeight :: (Int, Int) -> Int
+ Graphics.Rendering.MiniTypeset.MultiFont: lkpMultiFont' :: Ord fontfile => MultiFont fontfile style -> (Int, Int) -> style -> Char -> IO MultiFontGlyph
+ Graphics.Rendering.MiniTypeset.Render: renderBoundingBoxOutline :: AbsBox -> IO ()
+ Graphics.Rendering.MiniTypeset.Render: renderGapBoxOutline :: AbsBox -> IO ()
+ Graphics.Rendering.MiniTypeset.Render: renderInnerBoxOutline :: AbsBox -> IO ()
+ Graphics.Rendering.MiniTypeset.Render: renderOuterBoxOutline :: AbsBox -> IO ()
+ Graphics.Rendering.MiniTypeset.Render: renderQuadOutline :: Quad -> IO ()
- Graphics.Rendering.MiniTypeset.Box: realignBox :: WhichQuad -> Box -> Box
+ Graphics.Rendering.MiniTypeset.Box: realignBox :: WhichQuad -> Box -> (Pos, Box)
- Graphics.Rendering.MiniTypeset.FontTexture: FontTexture :: !Font -> !String -> !Float -> !Scaling -> !VerticalMetrics Float -> !UnicodeCache (Maybe BufLoc) -> !(Int, Int) -> !IORef TexCursor -> !IORef [TexBuf] -> !Double -> FontTexture
+ Graphics.Rendering.MiniTypeset.FontTexture: FontTexture :: !Font -> !String -> !(Float, Float) -> !Scaling -> !VerticalMetrics Float -> !UnicodeCache (Maybe BufLoc) -> !(Int, Int) -> !IORef TexCursor -> !IORef [TexBuf] -> !Double -> FontTexture
- Graphics.Rendering.MiniTypeset.FontTexture: [_ftexHeight] :: FontTexture -> !Float
+ Graphics.Rendering.MiniTypeset.FontTexture: [_ftexHeight] :: FontTexture -> !(Float, Float)
- Graphics.Rendering.MiniTypeset.FontTexture: newFontTexture' :: Font -> Float -> String -> (Int, Int) -> Double -> IO FontTexture
+ Graphics.Rendering.MiniTypeset.FontTexture: newFontTexture' :: Font -> (Float, Float) -> String -> (Int, Int) -> Double -> IO FontTexture
- Graphics.Rendering.MiniTypeset.Layout: HorizLine :: !Col -> !VAlign -> !Double -> !Double -> LayoutDecoration
+ Graphics.Rendering.MiniTypeset.Layout: HorizLine :: !Col -> !WhichQuad -> !VAlign -> !Double -> !Double -> LayoutDecoration
- Graphics.Rendering.MiniTypeset.MultiFont: mfAddNewFontTex :: Ord fontfile => MultiFont fontfile style -> (fontfile, Int) -> IO ()
+ Graphics.Rendering.MiniTypeset.MultiFont: mfAddNewFontTex :: Ord fontfile => MultiFont fontfile style -> (fontfile, (Int, Int)) -> IO ()
Files
- example/example-STIX.hs +15/−7
- minitypeset-opengl.cabal +2/−1
- src/Graphics/Rendering/MiniTypeset/Box.hs +124/−4
- src/Graphics/Rendering/MiniTypeset/Common.hs +56/−0
- src/Graphics/Rendering/MiniTypeset/Delimiters.hs +455/−0
- src/Graphics/Rendering/MiniTypeset/Document.hs +49/−52
- src/Graphics/Rendering/MiniTypeset/FontTexture.hs +11/−9
- src/Graphics/Rendering/MiniTypeset/Layout.hs +127/−31
- src/Graphics/Rendering/MiniTypeset/MultiFont.hs +22/−13
- src/Graphics/Rendering/MiniTypeset/Render.hs +27/−0
example/example-STIX.hs view
@@ -33,6 +33,11 @@ import UnicodeMath -------------------------------------------------------------------------------- + +-- | Font height +theHeight = Height 40 + +-------------------------------------------------------------------------------- -- * The \"document\" we want to render (normally you want to generate this) document :: Document String @@ -41,11 +46,11 @@ $ vcatR [ block12 -- , space - , hcatT [ vcat [ summation , over ] , (margin' 50 40 20 30 block3) ] + , hcatT [ vcat [ summation , hcatT [ over , space, fracs ] ] , (margin' 50 40 20 30 block3) ] , block4 ] -block12 = hcat [ block1 , Space , block2 ] +block12 = hcat [ delimited Brace block1 , Space , block2 ] block1 = Identified "block1" $ vcat [line1a,line1b,line1c,line1d] @@ -66,7 +71,7 @@ line1d = hcat [ "ut labore et " , Identified "dolore" $ boldItalic $ rgb 0 0 0.75 $ "dolore" - , " magna aliqua." + , " magn{a} aliqua." ] line2a = hcat [ "Ut enim ad " , Identified "bbox1" "minim" , " veniam," ] @@ -97,6 +102,8 @@ , string $ drop 13 math_test ] +fracs = blue $ hcat [ "1+", fraction (hcat [" xy+",fraction "z" "w"]) "pq" , space , choose "n" "k" , space , (choose' Square "m" "t") ] + subsup = vcat [ black "see if the gaps between lines..." , hcat [ supscript (char pp) "m" , space @@ -117,9 +124,10 @@ summation = vcat [ "summation" - , white $ hcat - [ aboveBelow (char sum_) (char infty , "n=0") , "f(n)" , space , space - , below "lim" (string ['x',rightarrow,infty]) , " g(x)" , space , space + , white $ Identified "zz" $ Delimited Paren + [ hcat [ aboveBelow (char sum_) (char infty , "n=0") , "f(n)" , space ] + , hcat [ space , below "lim" (string ['x',rightarrow,infty]) , " g(x)" , space ] + , " xyz A" ] , "and limits" ] @@ -210,7 +218,7 @@ mf <- readIORef theMultiFont -- create layout - lout <- createLayout mf (Height 40) document + lout <- createLayout mf theHeight document -- top-left corner of the rendered text let pos0 = Pos 16 16
minitypeset-opengl.cabal view
@@ -1,5 +1,5 @@ Name: minitypeset-opengl-Version: 0.2.0.1+Version: 0.3.0.0 Synopsis: Layout and render text with TrueType fonts using OpenGL Description: This is a library to render text with OpenGL. TrueType (and OpenType) fonts are supported; glyph rendering@@ -38,6 +38,7 @@ Graphics.Rendering.MiniTypeset.Common Graphics.Rendering.MiniTypeset.Document Graphics.Rendering.MiniTypeset.Layout+ Graphics.Rendering.MiniTypeset.Delimiters Graphics.Rendering.MiniTypeset.MultiFont Graphics.Rendering.MiniTypeset.FontTexture Graphics.Rendering.MiniTypeset.Render
src/Graphics/Rendering/MiniTypeset/Box.hs view
@@ -1,5 +1,5 @@ --- | Boxes are rectangular shapes used for layouting. They consisting of +-- | Boxes are rectangular shapes used for layouting. They are consisting of -- several quads having a relative position to each other: -- -- * \"inner boxes\" are used for aligning several boxes together@@ -26,6 +26,8 @@ -------------------------------------------------------------------------------- +import Data.List+ -- Semigroup became a superclass of Monoid at base 4.11 -- there are also conflicts between Monoid and Semigroup :( #if MIN_VERSION_base(4,11,0) @@ -81,6 +83,13 @@ x2 = max u2 p2 y2 = max v2 q2 +-- | Because it really should be a semigroup and not a monoid, it's important+-- that it's not implemented with foldl..+quadsLUB :: [Quad] -> Quad+quadsLUB [] = zeroQuad+quadsLUB [q] = q+quadsLUB qs = foldl1 quadLUB qs+ ofsLUB :: (Pos,Quad) -> (Pos,Quad) -> Quad ofsLUB (ofs1,quad1) (ofs2,quad2) = quadLUB (translate ofs1 quad1) (translate ofs2 quad2) @@ -103,6 +112,7 @@ instance Monoid Quad where mempty = zeroQuad mappend = quadLUB+ mconcat = quadsLUB #endif @@ -127,9 +137,26 @@ boxInnerQuad :: Box -> Quad boxInnerQuad (Box inner outer bounding gap) = Quad (0,0) inner +boxInnerWidth, boxInnerHeight :: Box -> Double+boxInnerWidth = fst . boxInnerSize+boxInnerHeight = snd . boxInnerSize+ emptyBox :: Box emptyBox = Box (0,0) zeroQuad zeroQuad zeroQuad +-- | Translates the quads relative to the inner quad.+shiftBox :: Pos -> Box -> Box+shiftBox ofs (Box sz outer bnd gap) = Box sz (translate ofs outer) (translate ofs bnd) (translate ofs gap)++boxSelectQuad :: WhichQuad -> Box -> Quad+boxSelectQuad which = case which of+ InnerQuad -> boxInnerQuad+ OuterQuad -> boxOuterQuad+ BoundingQuad -> boxBoundingQuad+ GapQuad -> boxGapQuad++--------------------------------------------------------------------------------+ -- | Enumerating the four different quads in a 'Box' data WhichQuad = InnerQuad@@ -140,20 +167,25 @@ -- | Replace the inner box by the given box. Since the inner box is used for -- alignment, this amounts to changing the alignment -realignBox :: WhichQuad -> Box -> Box+realignBox :: WhichQuad -> Box -> (Pos,Box) realignBox which box@(Box _ outer bounding gap) = case which of- InnerQuad -> box+ InnerQuad -> (Pos 0 0, box) OuterQuad -> realign outer BoundingQuad -> realign bounding GapQuad -> realign gap where- realign quad = Box (quadSize quad) (f outer) (f bounding) (f gap) where+ realign quad = (ofs, Box (quadSize quad) (f outer) (f bounding) (f gap)) where ofs = negate (pairToPos $ quadTopLeft quad) f :: Quad -> Quad f = translate ofs +-- | Replace the outer and gap boxes by the bounding box+trimBox :: Box -> Box+trimBox box@(Box size _ bounding _) = Box size bounding bounding bounding+ --------------------------------------------------------------------------------+-- * Absolute boxes -- | An absolute box data AbsBox = AbsBox@@ -177,6 +209,13 @@ absboxGapQuad :: AbsBox -> Quad absboxGapQuad (AbsBox ofs relbox) = translate ofs (boxGapQuad relbox) +absboxSelectQuad :: WhichQuad -> AbsBox -> Quad+absboxSelectQuad which = case which of+ InnerQuad -> absboxInnerQuad+ OuterQuad -> absboxOuterQuad+ BoundingQuad -> absboxBoundingQuad+ GapQuad -> absboxGapQuad+ -------------------------------------------------------------------------------- -- * Concatenating boxes @@ -357,6 +396,87 @@ Box (w0,h0) outer0 bound0 gap0 = box0 Box (w1,h1) outer1 bound1 gap1 = box1 Box (w2,h2) outer2 bound2 gap2 = box2++--------------------------------------------------------------------------------+-- * Fraction++fractionBox :: Double -> Box -> Box -> (Box,(Pos,Pos))+fractionBox vmargin box1 box2 = (box,(pos1,pos2)) where++ box = Box (w,h) outer bound gap ++ w = max w1 w2+ h = h1 -- + h2 -- ???++ x1 = 0.5 * (w-w1)+ x2 = 0.5 * (w-w2)++ y1 = - quadB outer1 - vmargin+ y2 = - quadT outer2 + vmargin++ pos1 = Pos x1 y1+ pos2 = Pos x2 y2++ outer = ofsLUB (pos1,outer1) (pos2,outer2)+ bound = ofsLUB (pos1,bound1) (pos2,bound2)+ gap = ofsLUB (pos1, gap1) (pos2, gap2)++ Box (w1,h1) outer1 bound1 gap1 = box1+ Box (w2,h2) outer2 bound2 gap2 = box2++--------------------------------------------------------------------------------+-- * delimiters++-- we have to vertically center the delimiters wrt. the bounding boxes +-- of the rest, and ignore them while computing the inner/outer boxes +-- (but include them for the bounding/gap boxes)+--+delimiterBox :: (Box,Box,Box) -> [Box] -> (Box,[Pos])+delimiterBox (left,mid,right) boxes = (box,posList) where+ h = maximum $ map boxInnerHeight boxes+ w = last gxs - quadWidth (boxGapQuad right) + boxInnerWidth right+ allb = left : intersperse mid boxes ++ right : [] + gxs = scanl (+) (quadL $ boxGapQuad left) $ map (quadWidth . boxGapQuad) allb+ xs = zipWith (-) gxs $ map (quadL . boxGapQuad) allb+ ys1 = [ h - boxInnerHeight b | b <- boxes ] + xs1 = odds xs++ outers = zipWith3 (\x y b -> translate (Pos x y) (boxOuterQuad b)) xs1 ys1 boxes+ outer1 = quadsLUB outers+ ho = quadHeight outer1+ yt = quadT outer1+ yc = yt + 0.5*ho+ yleft = yc - 0.5 * quadHeight (boxBoundingQuad left ) -- delimiters are trimmed+ ymid = yc - 0.5 * quadHeight (boxBoundingQuad mid )+ yright = yc - 0.5 * quadHeight (boxBoundingQuad right)++ ys2 = yleft : replicate (length boxes - 1) ymid ++ yright : []+ ys = interleave ys2 ys1+ posList = zipWith Pos xs ys+ aboxes = zipWith AbsBox posList allb+ bnd = quadsLUB (map absboxBoundingQuad aboxes)+ gap = quadsLUB (map absboxGapQuad aboxes)+ Quad (ox1,_) (ox2,_) = quadsLUB $ map absboxOuterQuad $ aboxes+ Quad (_,oy1) (_,oy2) = quadsLUB $ map absboxOuterQuad $ odds aboxes+ outer = Quad (ox1,oy1) (ox2,oy2)+ box = Box (w,h) outer bnd gap++--------------------------------------------------------------------------------++interleave :: [a] -> [a] -> [a]+interleave (x:xs) (y:ys) = x:y:interleave xs ys+interleave xs [] = xs+interleave [] ys = ys+ +odds :: [a] -> [a]+odds (x:y:rest) = y : odds rest+odds [x] = []+odds [] = []+ +evens :: [a] -> [a]+evens (x:y:rest) = x : evens rest+evens [x] = [x]+evens [] = [] --------------------------------------------------------------------------------
src/Graphics/Rendering/MiniTypeset/Common.hs view
@@ -86,6 +86,62 @@ -} --------------------------------------------------------------------------------+-- * Delimiters++data WhichDelim+ = LeftDelim+ | RightDelim+ deriving (Eq,Ord,Show) ++-- | A delimiter type+data Delimiter+ = Paren -- ^ parentheses (can stretch)+ | Square -- ^ square brackets (can stretch)+ | Brace -- ^ curly braces (can stretch)+ | Angle -- ^ angle brackets+ | Ceil -- ^ ceiling+ | Floor -- ^ floor+ | Top -- ^ top corners+ | Bottom -- ^ bottom corners+ | Guillemet -- ^ guillemet or french quote+ | AngleQuote -- ^ single quillemet or angle quote+ | VertSingle -- ^ vertical line (can stretch)+ | VertDouble -- ^ double vertical line (can stretch)+ | Tortoise -- ^ tortoise brackets+ deriving (Eq,Ord,Show)++delimiterChars :: Delimiter -> (Char,Char)+delimiterChars b = case b of+ Paren -> ( '(' , ')' )+ Square -> ( '[' , ']' )+ Brace -> ( '{' , '}' )+ Angle -> ( '\x2329' , '\x232a' )+ Ceil -> ( '\x2308' , '\x2309' )+ Floor -> ( '\x230a' , '\x230b' )+ Top -> ( '\x231c' , '\x231d' )+ Bottom -> ( '\x231e' , '\x231f' )+ AngleQuote -> ( '\x2039' , '\x203a' )+ Guillemet -> ( '\x00ab' , '\x00bb' )+ VertSingle -> ( '\x2223' , '\x2223' )+ VertDouble -> ( '\x2225' , '\x2225' )+ Tortoise -> ( '\x27ec' , '\x27ed' )++{-+ , "[[" ~> '\x27e6'+ , "]]" ~> '\x27e7'+ , "{|" ~> '\x2983'+ , "|}" ~> '\x2984'+ , "((" ~> '\x2985'+ , "))" ~> '\x2986'+ , "(|" ~> '\x2987'+ , "|)" ~> '\x2988'+ , "<|" ~> '\x2989'+ , "|>" ~> '\x298a'+ , "[|" ~> '\x27ec' -- tortoise shell bracket+ , "|]" ~> '\x27ed' -- tortoise shell bracket+-}++-------------------------------------------------------------------------------- -- * Positions -- | A position. We use screen-space coordinates here
+ src/Graphics/Rendering/MiniTypeset/Delimiters.hs view
@@ -0,0 +1,455 @@+ +-- | Automatically stretching\/growing (\*when possible) delimiters. +-- +-- No need to import this module directly. +-- +-- NOTE: these stretching delimiters are composed from overlayed unicode glyphs. +-- They are designed to work with the STIX fonts, other fonts may produce +-- unacceptable results. Transparent rendering is broken too (though that could +-- be fixed in principle). +-- +-- TODO: +-- +-- * growing ceil\/floor +-- +-- * \"compound\" brackets like @[[@, @{|@, etc +-- +-- * fix subscripts and superscripts of big delimited things +-- +-- * cleaner implementation +-- +-- * maybe hardwire the required glyphs from STIX so that it works with any font? +-- +-- * fix transparency +-- + + +{-# LANGUAGE BangPatterns, Rank2Types #-} +module Graphics.Rendering.MiniTypeset.Delimiters where + +-------------------------------------------------------------------------------- + +import Data.Ord +import Data.Char hiding ( Space ) +import Data.List + +import Control.Monad + +import Graphics.Rendering.MiniTypeset.Common +import Graphics.Rendering.MiniTypeset.Document +import Graphics.Rendering.MiniTypeset.Box + +{- +-- used when generating code +import Text.Printf +import qualified Data.Map as Map ; import Data.Map (Map) +import Graphics.Rendering.MiniTypeset.Layout +import Graphics.Rendering.MiniTypeset.MultiFont +-} + +-------------------------------------------------------------------------------- + +delimHangAbove = 0.125 :: Double +delimHangBelow = -0.075 :: Double +delimHMargin = 0.075 :: Double +delimVMargin = 0.075 :: Double + +-------------------------------------------------------------------------------- + +-- | A compound delimiter is built from overlayed Unicode glyphs. +-- It can be either fixed (a single glyph; two glyphs next to each other), or adjustable +-- (glyphs with adjustable overlap) + +data CompoundDelim + = FixDelim (forall a. Document a) -- ^ something whose size is fixed + | Adjustable (forall a. Double -> Document a) -- ^ something whose size can be adjusted + +sizedCompoundDelim :: CompoundDelim -> Double -> Document a +sizedCompoundDelim cd x = case cd of + FixDelim d -> Realign BoundingQuad $ Trim $ UnsafeResize (1,x) d + Adjustable f -> Realign BoundingQuad $ Trim $ f x + +-------------------------------------------------------------------------------- +-- * Utility + +rescale :: (Double,Double) -> Double -> Double +rescale (!a,!b) !x + | x < a = 0 + | x < b = (x-a)/(b-a) + | otherwise = 1 + +rescaleTo :: (Double,Double) -> (Double,Double) -> Double -> Double +rescaleTo (a,b) (c,d) !x = c + (d-c) * rescale (a,b) x + +fdivmod :: Double -> Double -> (Int,Double) +fdivmod a b = (n,x) where + n = floor (a/b) + x = (a - fromIntegral n * b) / b + +-------------------------------------------------------------------------------- + +symmNegMargin :: Double -> Document a -> Document a +symmNegMargin y = AddMargin (Margin 0 0 (-y) (-y)) + +topNegMargin :: Double -> Document a -> Document a +topNegMargin y = AddMargin (Margin 0 0 (-y) 0) + +botNegMargin :: Double -> Document a -> Document a +botNegMargin y = AddMargin (Margin 0 0 0 (-y)) + +-------------------------------------------------------------------------------- +-- * Growing delimiters + +type DelimGrower a = Height -> WhichDelim -> Double -> Document a + +data DelimImpl + = GrowingDelim (forall a. DelimGrower a) + | FixedDelim !(Char,Char) +-- | NotImplDelim + +delimiterImpl :: Delimiter -> DelimImpl +delimiterImpl delim = case delim of + Paren -> GrowingDelim growParen + Brace -> GrowingDelim growBrace + Square -> GrowingDelim growBracket + VertSingle -> GrowingDelim growVertical + VertDouble -> GrowingDelim growDblVertical + otherwise -> FixedDelim (delimiterChars delim) + +finalDelim :: Height -> Delimiter -> Double -> WhichDelim -> Document a +finalDelim = finalDelim' 0 + +finalDelim' :: Double -> Height -> Delimiter -> Double -> WhichDelim -> Document a +finalDelim' yofs height@(Height h) delim target_in_pixels which = final where + final = RePosition (Pos 0 vofs) $ AddMargin (Margin mh mh mv mv) $ trimmed + vofs = yofs {- - fh * delimHangBelow -} -- align on bottom! + mh = fh * delimHMargin + mv = fh * delimVMargin + trimmed = case delimiterImpl delim of + GrowingDelim grow -> grow height which target + FixedDelim (lch,rch) -> UnsafeResize (1, min 3 target) $ + Realign BoundingQuad $ + Trim $ Symbol $ + case which of { LeftDelim -> lch ; RightDelim -> rch } + fh = fromIntegral h :: Double + extra = fh * (delimHangAbove - delimHangBelow) + target = (target_in_pixels + extra) / fh + +-------------------------------------------------------------------------------- +-- * Figuring out how to build a delimiter of the target size + +-- | Note: target height is relative to the font height, but not including line gap! +-- You have to take line gap into account yourself if necessary. +growBrace :: Height -> WhichDelim -> Double -> Document a +growBrace height which target + | y < 1.425 = sizedCompoundDelim (buildBrace height 0 which) (rescaleTo (0.648,2.758) (0.700,3.000) y) + | y < 3.204 = sizedCompoundDelim (buildBrace height 1 which) (rescaleTo (1.425,6.136) (0.700,3.000) y) + | y < 4.504 = sizedCompoundDelim (buildBrace height 2 which) (rescaleTo (3.204,4.464) (0.000,1.000) y) + | y < 6.424 = sizedCompoundDelim (buildBrace height 3 which) (rescaleTo (4.504,6.424) (0.000,1.000) y) + | y < 8.344 = sizedCompoundDelim (buildBrace height 4 which) (rescaleTo (6.424,8.344) (0.000,1.000) y) + | y < 10.264 = sizedCompoundDelim (buildBrace height 5 which) (rescaleTo (8.344,10.264) (0.000,1.000) y) + | y < 12.184 = sizedCompoundDelim (buildBrace height 6 which) (rescaleTo (10.264,12.184) (0.000,1.000) y) + | otherwise = let (n,x) = fdivmod (y - 12.184) 1.920 + fn = fromIntegral n + in sizedCompoundDelim (buildBrace height (n+7) which) (rescaleTo (0.000,1.000) (0.000,1.000) x) + where + y = target + (-0.078) + +growParen :: Height -> WhichDelim -> Double -> Document a +growParen height which target + | y < 2.047 = sizedCompoundDelim (buildParen height 0 which) (rescaleTo (0.645,2.750) (0.700,3.000) y) + | y < 1.761 = sizedCompoundDelim (buildParen height 1 which) (rescaleTo (2.047,2.527) (0.000,1.000) y) + | y < 2.701 = sizedCompoundDelim (buildParen height 2 which) (rescaleTo (1.761,7.613) (0.700,3.000) y) + | y < 3.695 = sizedCompoundDelim (buildParen height 3 which) (rescaleTo (2.701,3.761) (0.000,1.000) y) + | y < 4.909 = sizedCompoundDelim (buildParen height 4 which) (rescaleTo (3.695,4.975) (0.000,1.000) y) + | y < 6.122 = sizedCompoundDelim (buildParen height 5 which) (rescaleTo (4.909,6.189) (0.000,1.000) y) + | y < 7.336 = sizedCompoundDelim (buildParen height 6 which) (rescaleTo (6.122,7.403) (0.000,1.000) y) + | otherwise = let (n,x) = fdivmod (y - 7.336) 1.214 + fn = fromIntegral n + in sizedCompoundDelim (buildParen height (n+7) which) (rescaleTo (0.000,1.054) (0.000,1.000) x) + where + y = target + (-0.082) + +growBracket :: Height -> WhichDelim -> Double -> Document a +growBracket height which target + | y < 2.055 = sizedCompoundDelim (buildBracket height 0 which) (rescaleTo (0.648,2.758) (0.700,3.000) y) + | y < 2.555 = sizedCompoundDelim (buildBracket height 1 which) (rescaleTo (2.055,2.535) (0.000,1.000) y) + | y < 3.235 = sizedCompoundDelim (buildBracket height 2 which) (rescaleTo (2.555,3.515) (0.000,1.000) y) + | y < 4.315 = sizedCompoundDelim (buildBracket height 3 which) (rescaleTo (3.235,4.475) (0.000,1.000) y) + | y < 5.275 = sizedCompoundDelim (buildBracket height 4 which) (rescaleTo (4.315,5.435) (0.000,1.000) y) + | y < 6.235 = sizedCompoundDelim (buildBracket height 5 which) (rescaleTo (5.275,6.395) (0.000,1.000) y) + | y < 7.195 = sizedCompoundDelim (buildBracket height 6 which) (rescaleTo (6.235,7.355) (0.000,1.000) y) + | otherwise = let (n,x) = fdivmod (y - 7.195) 0.960 + fn = fromIntegral n + in sizedCompoundDelim (buildBracket height (n+7) which) (rescaleTo (0.000,1.167) (0.000,1.000) x) + where + y = target + (-0.078) + +growVertical :: Height -> WhichDelim -> Double -> Document a +growVertical height which target + | y < 1.455 = sizedCompoundDelim (buildVertical height 0 which) (rescaleTo (0.633,2.703) (0.700,3.000) y) + | y < 1.929 = sizedCompoundDelim (buildVertical height 1 which) (rescaleTo (1.455,1.785) (0.000,1.000) y) + | y < 2.792 = sizedCompoundDelim (buildVertical height 2 which) (rescaleTo (1.929,3.529) (0.000,1.000) y) + | y < 3.654 = sizedCompoundDelim (buildVertical height 3 which) (rescaleTo (2.792,4.392) (0.000,1.000) y) + | y < 4.516 = sizedCompoundDelim (buildVertical height 4 which) (rescaleTo (3.654,5.254) (0.000,1.000) y) + | y < 5.379 = sizedCompoundDelim (buildVertical height 5 which) (rescaleTo (4.516,6.116) (0.000,1.000) y) + | y < 6.241 = sizedCompoundDelim (buildVertical height 6 which) (rescaleTo (5.379,6.979) (0.000,1.000) y) + | otherwise = let (n,x) = fdivmod (y - 6.241) 0.862 + fn = fromIntegral n + in sizedCompoundDelim (buildVertical height (n+7) which) (rescaleTo (0.000,1.855) (0.000,1.000) x) + where + y = target + (-0.098) + +growDblVertical :: Height -> WhichDelim -> Double -> Document a +growDblVertical height which target + | y < 1.455 = sizedCompoundDelim (buildDblVertical height 0 which) (rescaleTo (0.633,2.703) (0.700,3.000) y) + | y < 1.929 = sizedCompoundDelim (buildDblVertical height 1 which) (rescaleTo (1.455,1.785) (0.000,1.000) y) + | y < 2.792 = sizedCompoundDelim (buildDblVertical height 2 which) (rescaleTo (1.929,3.529) (0.000,1.000) y) + | y < 3.654 = sizedCompoundDelim (buildDblVertical height 3 which) (rescaleTo (2.792,4.392) (0.000,1.000) y) + | y < 4.516 = sizedCompoundDelim (buildDblVertical height 4 which) (rescaleTo (3.654,5.254) (0.000,1.000) y) + | y < 5.379 = sizedCompoundDelim (buildDblVertical height 5 which) (rescaleTo (4.516,6.116) (0.000,1.000) y) + | y < 6.241 = sizedCompoundDelim (buildDblVertical height 6 which) (rescaleTo (5.379,6.979) (0.000,1.000) y) + | otherwise = let (n,x) = fdivmod (y - 6.241) 0.862 + fn = fromIntegral n + in sizedCompoundDelim (buildDblVertical height (n+7) which) (rescaleTo (0.000,1.855) (0.000,1.000) x) + where + y = target + (-0.098) + +-------------------------------------------------------------------------------- +-- * Delimiter builders + +type CompoundLevel = Int + +type DelimBuilder = Height -> CompoundLevel -> WhichDelim -> CompoundDelim + +buildBrace :: DelimBuilder +buildBrace (Height h) n lr + | n == 0 = FixDelim $ one + | n == 1 = FixDelim $ vcat [ botNegMargin (0.01*fh) top2 , topNegMargin (0.01*fh) bot2 ] + | n == 2 = Adjustable $ \x -> + let y = 0.02 + (1-x)*0.63 + in vcat [ top3 , symmNegMargin (y*fh) mid3 , bot3 ] + | otherwise = Adjustable $ \x -> + let y = 0.02 + (1-x)*0.48 + adj = symmNegMargin (y *fh) ext3 + fix = symmNegMargin (0.02*fh) ext3 + in vcat (top3 : replicate (n-3) fix ++ adj : mid3 : adj : replicate (n-3) fix ++ bot3 : []) + where + fh = fromIntegral h :: Double + mk ch = Trim (char ch) + + one = mk $ case lr of { LeftDelim -> '{' ; RightDelim -> '}' } + + top2 = mk $ case lr of { LeftDelim -> braceSection1 ; RightDelim -> braceSection2 } + bot2 = mk $ case lr of { LeftDelim -> braceSection2 ; RightDelim -> braceSection1 } + + top3 = mk $ case lr of { LeftDelim -> lbraceTop ; RightDelim -> rbraceTop } + mid3 = mk $ case lr of { LeftDelim -> lbraceMid ; RightDelim -> rbraceMid } + bot3 = mk $ case lr of { LeftDelim -> lbraceBot ; RightDelim -> rbraceBot } + ext3 = mk $ lrBraceExt + +-------------------------------------------------------------------------------- + +buildParen :: DelimBuilder +buildParen (Height h) n lr + | n == 0 = FixDelim $ one + | n == 1 = Adjustable $ \x -> let y = 0.02 + (1-x)*0.48 in vcat [ top , topNegMargin (y*fh) bot ] + | n == 2 = FixDelim $ vcat [ top , topNegMargin (0.02*fh) bot ] -- parens suck in this font + | n == 3 = Adjustable $ \x -> + let y = 0.02 + (1-x)*0.53 + adj = symmNegMargin (y *fh) ext + in vcat (top : adj : bot : []) + | otherwise = Adjustable $ \x -> + let y = 0.02 + (1-x)*0.32 + adj = symmNegMargin (y *fh) ext + fix = symmNegMargin (0.02*fh) ext + in vcat (top : adj : replicate (n-4) fix ++ adj : bot : []) + where + fh = fromIntegral h :: Double + mk ch = Trim (char ch) + + one = mk $ case lr of { LeftDelim -> '(' ; RightDelim -> ')' } + top = mk $ case lr of { LeftDelim -> lparenTop ; RightDelim -> rparenTop } + ext = mk $ case lr of { LeftDelim -> lparenExt ; RightDelim -> rparenExt } + bot = mk $ case lr of { LeftDelim -> lparenBot ; RightDelim -> rparenBot } + +-------------------------------------------------------------------------------- + +buildBracket :: DelimBuilder +buildBracket (Height h) n lr + | n == 0 = FixDelim $ one + | n == 1 = Adjustable $ \x -> let y = 0.02 + (1-x)*0.48 in vcat [ top , topNegMargin (y*fh) bot ] + | n == 2 = Adjustable $ \x -> + let y = 0.02 + (1-x)*0.53 + adj = symmNegMargin (y *fh) ext + in vcat (top : adj : bot : []) + | n == 3 = Adjustable $ \x -> + let y = 0.02 + (1-x)*0.31 + adj = symmNegMargin (y *fh) ext + in vcat (top : adj : adj : bot : []) + | otherwise = Adjustable $ \x -> + let y = 0.02 + (1-x)*0.28 + adj = symmNegMargin (y *fh) ext + fix = symmNegMargin (0.02*fh) ext + in vcat (top : adj : replicate (n-3) fix ++ adj : bot : []) + where + fh = fromIntegral h :: Double + mk ch = Trim (char ch) + + one = mk $ case lr of { LeftDelim -> '[' ; RightDelim -> ']' } + top = mk $ case lr of { LeftDelim -> lbracketTop ; RightDelim -> rbracketTop } + ext = mk $ case lr of { LeftDelim -> lbracketExt ; RightDelim -> rbracketExt } + bot = mk $ case lr of { LeftDelim -> lbracketBot ; RightDelim -> rbracketBot } + +-------------------------------------------------------------------------------- + +buildVertical :: DelimBuilder +buildVertical (Height h) n _lr_ + | n == 0 = FixDelim $ one + | n == 1 = Adjustable $ \x -> let y = 0.02 + (1-x)*0.33 in vcat [ one , topNegMargin (y*fh) one ] + | otherwise = Adjustable $ \x -> + let y = 0.02 + (1-x)*0.40 + adj = symmNegMargin (y *fh) one + fix = symmNegMargin (0.02*fh) one + in vcat (one : adj : replicate (n-2) fix ++ adj : one : []) + where + fh = fromIntegral h :: Double + mk ch = Trim (char ch) + + one = mk '\x2223' + +buildDblVertical :: DelimBuilder +buildDblVertical (Height h) n _lr_ + | n == 0 = FixDelim $ one + | n == 1 = Adjustable $ \x -> let y = 0.02 + (1-x)*0.33 in vcat [ one , topNegMargin (y*fh) one ] + | otherwise = Adjustable $ \x -> + let y = 0.02 + (1-x)*0.40 + adj = symmNegMargin (y *fh) one + fix = symmNegMargin (0.02*fh) one + in vcat (one : adj : replicate (n-2) fix ++ adj : one : []) + where + fh = fromIntegral h :: Double + mk ch = Trim (char ch) + + one = mk '\x2225' + +-------------------------------------------------------------------------------- +-- * Unicode codepoint constants + +lparenTop = '\x239b' +lparenExt = '\x239c' +lparenBot = '\x239d' + +rparenTop = '\x239e' +rparenExt = '\x239f' +rparenBot = '\x23a0' + +lbracketTop = '\x23a1' +lbracketExt = '\x23a2' +lbracketBot = '\x23a3' + +rbracketTop = '\x23a4' +rbracketExt = '\x23a5' +rbracketBot = '\x23a6' + +lbraceTop = '\x23a7' +lbraceMid = '\x23a8' +lbraceBot = '\x23a9' + +lrBraceExt = '\x23aa' + +rbraceTop = '\x23ab' +rbraceMid = '\x23ac' +rbraceBot = '\x23ad' + +intTop = '\x2320' +intExt = '\x23ae' +intBot = '\x2321' + +braceSection1 = '\x23b0' +braceSection2 = '\x23b1' + +-------------------------------------------------------------------------------- +{- /// CODE GENERATION /// + +measure :: Ord fontfile => MultiFont fontfile style -> Height -> Document String -> IO Double +measure mf (Height h) doc0 = do + let doc = Identified ("measure" :: String) $ Trim doc0 + lout <- createLayout mf (Height h) doc + usertable <- dryrunLayout lout (Pos 0 0) + let AbsBox _ box = (Map.!) usertable "measure" + let res = quadHeight $ boxBoundingQuad box + return (res / fromIntegral h) + +-------------------------------------------------------------------------------- + +testDelimBuilder :: Ord fontfile => MultiFont fontfile style -> DelimBuilder -> IO () +testDelimBuilder mf builder = do + let h = Height 256 + forM_ [0..5] $ \n -> do + putStrLn $ "level (n) = " ++ show n + let cdelim = builder h n LeftDelim + case cdelim of + FixDelim mkdoc -> do + putStr "Fixed -> " + list <- forM [0.75,0.875..1.5] $ \x -> measure mf h (Trim $ UnsafeResize (1,x) mkdoc) + print list + Adjustable mkdoc -> do + putStr "Adjustable -> " + list <- forM [0,0.1..1] $ \x -> measure mf h (mkdoc x) + print list + +-------------------------------------------------------------------------------- + +-- | Generate code for automatically sizing growable delimiters +writeGrowingDelimFromMeasurement :: Ord fontfile => MultiFont fontfile style -> String -> DelimBuilder -> IO [String] +writeGrowingDelimFromMeasurement mf what builder = do + let ht = Height 256 + which = LeftDelim + base <- case (builder ht 0 which) of { FixDelim doc -> measure mf ht doc } + let ofs = base - 1 + let candi1 n = let cd = builder ht n LeftDelim in case cd of + FixDelim doc -> [ ((n,x) , Trim (UnsafeResize (1,x) doc) ) | x <- [0.7,0.75..3.0] ] + Adjustable mkdoc -> [ ((n,x) , mkdoc x ) | x <- [0,0.025..1.0] ] + let candidates = concat [ candi1 n | n<-[0..7] ] + hs <- forM candidates $ \((n,x),doc) -> measure mf ht doc + let sorted = sortBy (comparing fst) $ zip hs candidates + groups = [ [ ((k,x),h) | (h,((k,x),doc)) <- sorted , k==n ] | n <- [0..7] ] + smallest = map head groups + largest = map last groups + + let choices = + [ " | y < " ++ printf "%.3f" h2 ++ + " = sizedCompoundDelim (" ++ what ++ " height " ++ show k1a ++ " which) " ++ + (printf "(rescaleTo (%.3f,%.3f) (%.3f,%.3f) y)" h1a h1b x1a x1b) + | ( ( ((k1a,x1a),h1a) , ((k2,x2),h2) ) , ((k1b,x1b),h1b) ) <- zip (pairs smallest) largest + ] + + let ( ( ((k1a,x1a),h1a) , ((k2a ,x2a ),h2a ) ) , ( ((k1b,x1b),h1b) , ((k2b,x2b),h2b) ) ) = last (zip (pairs smallest) (pairs largest)) + extrap = + [ " | otherwise = let (n,x) = " ++ printf "fdivmod (y - %.3f) %.3f" h2a (h2a-h1a) + , " fn = fromIntegral n " + , " in sizedCompoundDelim (" ++ what ++ " height " ++ printf "(n+%d)" (k1a+1) ++ " which) " ++ + (printf "(rescaleTo (%.3f,%.3f) (%.3f,%.3f) x)" ((h1a-h1a)/(h2a-h1a)) ((h1b-h1a)/(h2a-h1a)) x1a x1b) + ] + + let ls = + [ "grow :: Height -> WhichDelim -> Double -> Document a" + , "grow height which target" + ] + ++ choices + ++ extrap ++ + [ " where " + , " y = target + " ++ printf "(%.3f)" ofs + ] + putStrLn $ unlines ls + return ls + + +pairs :: [a] -> [(a,a)] +pairs (x:xs@(y:_)) = (x,y) : pairs xs +pairs [x] = [] +pairs [] = [] + +-} +--------------------------------------------------------------------------------
src/Graphics/Rendering/MiniTypeset/Document.hs view
@@ -2,10 +2,11 @@ -- | The document type, which expresses the intent of the user about -- what to render. ----- We support general layouting \/ formatting, and also construction+-- We support general layouting \/ formatting, and also constructions -- specific to mathematical documents (similar to LaTeX). ----- TODO: fractions, brackets, mathemetical accents, compound symbols+-- TODO: mathemetical accents, compound symbols, +-- user-defined styles, squiggly underlines, etc -- {-# LANGUAGE OverloadedStrings, BangPatterns #-}@@ -29,21 +30,26 @@ -- different parts of the rendered text. It must have an 'Ord' instance. -- data Document ident- = Symbol !Char -- ^ a single character or symbol- | String !String -- ^ a string - | Space -- ^ a space character (do we need this to be separate?)- | HorzCat !VAlign [Document ident] -- ^ horizontal concatenation- | VertCat !HAlign [Document ident] -- ^ vertical concatenation- | Overlay !(HAlign,VAlign) [Document ident] -- ^ overlaying on the top of each other- | SubSupScript !(SubSup ident) !(Document ident) -- ^ add subscript and\/or superscript- | AboveBelow !(AboveBelow ident) !(Document ident) -- ^ above\/below (like in a summation or limit)- | WithColor !Col !(Document ident) -- ^ change color- | WithStyle !BasicStyle !(Document ident) -- ^ change font family- | Decorated !TextDecoration !(Document ident) -- ^ add text decoration- | Identified !ident !(Document ident) -- ^ user identifier so that the layout engine can return position information- | AddMargin !Margin !(Document ident) -- ^ an extra margin around the document- | Realign !WhichQuad !(Document ident) -- ^ change the alignment box- | EmptyDoc -- ^ the empty document+ = Symbol !Char -- ^ a single character or symbol+ | String !String -- ^ a string + | Space -- ^ a space character (do we need this to be separate?)+ | HorzCat !VAlign [Document ident] -- ^ horizontal concatenation+ | VertCat !HAlign [Document ident] -- ^ vertical concatenation+ | Overlay !(HAlign,VAlign) [Document ident] -- ^ overlaying on the top of each other+ | SubSupScript !(SubSup ident) !(Document ident) -- ^ add subscript and\/or superscript+ | Delimited !Delimiter [Document ident] -- ^ automatically sized (when possible) delimiters+ | Fraction !Bool !(Document ident) !(Document ident) -- ^ fractions (the Bool signifies whether to draw the line)+ | AboveBelow !(AboveBelow ident) !(Document ident) -- ^ above\/below (like in a summation or limit)+ | WithColor !Col !(Document ident) -- ^ change color+ | WithStyle !BasicStyle !(Document ident) -- ^ change font family+ | Decorated !TextDecoration !(Document ident) -- ^ add text decoration+ | AddMargin !Margin !(Document ident) -- ^ an extra margin around the document fragment+ | Realign !WhichQuad !(Document ident) -- ^ change the alignment box+ | Trim !(Document ident) -- ^ trim the outer \& gap boxes to the bounding box+ | RePosition !Pos !(Document ident) -- ^ offset (mostly for internal usage)+ | UnsafeResize !(Double,Double) !(Document ident) -- ^ temporary hack for internal usage, DO NOT USE IT! + | Identified !ident !(Document ident) -- ^ user identifier so that the layout engine can return position information+ | EmptyDoc -- ^ the empty document deriving (Eq,Ord,Show) --------------------------------------------------------------------------------@@ -53,6 +59,7 @@ = Underline | Overline | StrikeThrough+-- | SquigglyUnderline deriving (Eq,Ord,Show) --------------------------------------------------------------------------------@@ -147,7 +154,7 @@ vcatR :: [Document a] -> Document a vcatR = VertCat AlignRight --- * Subscript and superscript+-- ** Subscript and superscript subscript :: Document a -> Document a -> Document a subscript doc sub = SubSupScript (Subscript sub) doc@@ -158,7 +165,7 @@ subSup :: Document a -> (Document a, Document a) -> Document a subSup doc (sub,sup) = SubSupScript (SubAndSupscript sub sup) doc --- * Above and below+-- ** Above and below -- | Used for \"big\" mathematical operators (like summation) above :: Document a -> Document a -> Document a@@ -170,14 +177,33 @@ aboveBelow :: Document a -> (Document a, Document a) -> Document a aboveBelow doc (ab,be) = AboveBelow (AboveAndBelow ab be) doc --- * Text decoration+-- ** Fractions and delimiters +fraction :: Document a -> Document a -> Document a+fraction = Fraction True++-- | \"n choose k\" notation+choose :: Document a -> Document a -> Document a+choose = choose' Paren++choose' :: Delimiter -> Document a -> Document a -> Document a+choose' delim above below = delimited delim (Fraction False above below)++delimited :: Delimiter -> Document a -> Document a+delimited delim doc = Delimited delim [doc]++-- | Puts a matched vertical line between the parts+delimiteds :: Delimiter -> [Document a] -> Document a+delimiteds delim docs = Delimited delim docs++-- ** Text decoration+ underline, overline, strike :: Document a -> Document a underline = Decorated Underline overline = Decorated Overline strike = Decorated StrikeThrough --- * Font variations+-- ** Font variations regular, bold, italic, boldItalic :: Document a -> Document a regular = WithStyle Regular@@ -185,7 +211,7 @@ italic = WithStyle Italic boldItalic = WithStyle BoldItalic --- * Colors+-- ** Colors white, black, red, green, blue :: Document a -> Document a white = WithColor (Col 1 1 1)@@ -197,7 +223,7 @@ rgb :: Float -> Float -> Float -> Document a -> Document a rgb r g b = WithColor (Col r g b) --- * Margins+-- ** Margins margin :: Double -> Document a -> Document a margin x = AddMargin (Margin x x x x)@@ -210,34 +236,5 @@ margin' :: Double -> Double -> Double -> Double -> Document a -> Document a margin' l r t b = AddMargin (Margin l r t b)------------------------------------------------------------------------------------- * Brackets (not implemented yet)--data Bracket- = Paren- | Square- | Brace- | Angle -- 2329 / 232a- | Ceil -- 2308 / 2309- | Floor -- 230a / 230b- | Top -- 231c / 231d- | Bottom -- 231e / 231f- | AngleQuote -- 2039 / 203a- | FrenchQuote -- 00ab / 00bb- deriving (Eq,Ord,Show)--bracketChars :: Bracket -> (Char,Char)-bracketChars b = case b of- Paren -> ( '(' , ')' )- Square -> ( '[' , ']' )- Brace -> ( '{' , '}' )- Angle -> ( '\x2329' , '\x232a' )- Ceil -> ( '\x2308' , '\x2309' )- Floor -> ( '\x230a' , '\x230b' )- Top -> ( '\x231c' , '\x231d' )- Bottom -> ( '\x231e' , '\x231f' )- AngleQuote -> ( '\x2039' , '\x203a' )- FrenchQuote -> ( '\x00ab' , '\x00bb' ) --------------------------------------------------------------------------------
src/Graphics/Rendering/MiniTypeset/FontTexture.hs view
@@ -126,7 +126,7 @@ data FontTexture = FontTexture { _ftexFont :: !Font , _ftexName :: !String - , _ftexHeight :: !Float + , _ftexHeight :: !(Float,Float) -- x and y height , _ftexScaling :: !Scaling , _ftexVM :: !(VerticalMetrics Float) , _ftexChars :: !(UnicodeCache (Maybe BufLoc)) @@ -146,15 +146,17 @@ defaultTextureSize = (512,512) -- (128,128) -- (512,512) -- (1024,1024) newFontTexture :: Font -> Float -> String -> IO FontTexture -newFontTexture font height name = newFontTexture' font height name defaultTextureSize 1 +newFontTexture font height name = newFontTexture' font (height,height) name defaultTextureSize 1 --- | Creates a new (empty) font texture -newFontTexture' :: Font -> Float -> String -> (Int,Int) -> Double -> IO FontTexture -newFontTexture' font height name size lgapfactor = do +-- | Creates a new (empty) font texture. We allow different horizontal and vertical scaling, +-- but both are measured in /pixel heights/ +newFontTexture' :: Font -> (Float,Float) -> String -> (Int,Int) -> Double -> IO FontTexture +newFontTexture' font (xheight,yheight) name size lgapfactor = do uc <- newUnicodeCache vmu <- getFontVerticalMetrics font - let s = scaleForPixelHeight vmu height - vms = fmap (scaleU s) vmu + let sx = scaleForPixelHeight vmu xheight + sy = scaleForPixelHeight vmu yheight + vms = fmap (scaleU sy) vmu -- print vmu -- print vms @@ -164,8 +166,8 @@ let ftex = FontTexture { _ftexFont = font , _ftexName = name - , _ftexHeight = height - , _ftexScaling = (s,s) + , _ftexHeight = (xheight,yheight) + , _ftexScaling = (sx,sy) , _ftexVM = vms , _ftexChars = uc , _ftexBufSize = size
src/Graphics/Rendering/MiniTypeset/Layout.hs view
@@ -6,6 +6,8 @@ -------------------------------------------------------------------------------- +import Data.List ( intersperse ) + import Control.Monad import Data.IORef @@ -20,10 +22,13 @@ import Graphics.Rendering.MiniTypeset.Common import Graphics.Rendering.MiniTypeset.Box import Graphics.Rendering.MiniTypeset.Document +import Graphics.Rendering.MiniTypeset.Delimiters import Graphics.Rendering.MiniTypeset.FontTexture import Graphics.Rendering.MiniTypeset.MultiFont import Graphics.Rendering.MiniTypeset.Render +-- import qualified Unsafe.Coerce as Unsafe -- debugging only! + -------------------------------------------------------------------------------- -- * Relative position and size constants (mathematical coordinate system!) @@ -33,32 +38,61 @@ underlinePos = -0.10 :: Double -- Underline relative position overlinePos = 0.10 :: Double -- Overline relative position -strikeThroughPos = 0.48 :: Double -- Strike-through relative position +strikeThroughPos = 0.29 :: Double -- Strike-through relative position horizLineWidth = 0.045 :: Double -- Text decoration line width abovePos = 0.15 :: Double belowPos = -0.15 :: Double +fractionSize = 0.9 :: Double -- first-level fraction size +fracLinePos = 0.32 - 0.08 :: Double -- vertical position of the fraction line +fracYMargin = 0.08 :: Double + -------------------------------------------------------------------------------- -- * Subscript size indexing -- | 0 is the default size, 1 is smaller, 2 is even smaller, etc (each subscript -newtype SizeIndex - = SizeIndex Int +data SizeIndex + = NormalSize -- ^ normal text size + | FractionSize -- ^ first-level fraction + | ScriptSize1 -- ^ first-level subscript + | ScriptSize2 -- ^ second-level subscript + | ScriptSize3 -- ^ third-level subscript + | CustomSize !(Double,Double) !SizeIndex -- ^ temporary hack deriving (Eq,Ord,Show) -succSizeIndex :: SizeIndex -> SizeIndex -succSizeIndex (SizeIndex n) = SizeIndex (n+1) +scriptSuccSizeIndex :: SizeIndex -> SizeIndex +scriptSuccSizeIndex idx = case idx of + NormalSize -> ScriptSize1 + FractionSize -> ScriptSize1 + ScriptSize1 -> ScriptSize2 + ScriptSize2 -> ScriptSize3 + ScriptSize3 -> ScriptSize3 + CustomSize {} -> error "scriptSuccSizeIndex: Custom" -calculateSizeHeight :: Height -> SizeIndex -> Int -calculateSizeHeight (Height height) = go where - go (SizeIndex n) - | n == 0 = height - | n == 1 = round (fromIntegral height * subSupSize) - | n == 2 = round (fromIntegral height * subSupSize * subSupSize) - | n == 3 = round (fromIntegral height * subSupSize * subSupSize * 0.8) - | n > 3 = go (SizeIndex 3) +fracSuccSizeIndex :: SizeIndex -> SizeIndex +fracSuccSizeIndex idx = case idx of + NormalSize -> FractionSize + FractionSize -> ScriptSize1 + ScriptSize1 -> ScriptSize2 + ScriptSize2 -> ScriptSize3 + ScriptSize3 -> ScriptSize3 + CustomSize {} -> error "fracSuccSizeIndex: Custom" +calculateSizeXHeight :: Height -> SizeIndex -> Int +calculateSizeXHeight ht@(Height height) idx = case idx of + CustomSize (x,y) si -> round (fromIntegral (calculateSizeXHeight ht si) * x) + _ -> calculateSizeYHeight (Height height) idx + +calculateSizeYHeight :: Height -> SizeIndex -> Int +calculateSizeYHeight ht@(Height height) idx = case idx of + NormalSize -> height + FractionSize -> round (fromIntegral height * fractionSize) + ScriptSize1 -> round (fromIntegral height * subSupSize) + ScriptSize2 -> round (fromIntegral height * subSupSize * subSupSize) + ScriptSize3 -> round (fromIntegral height * subSupSize * subSupSize * 0.8) + CustomSize (x,y) si -> round (fromIntegral (calculateSizeYHeight ht si) * y) + -------------------------------------------------------------------------------- -- * The layout data type @@ -78,6 +112,7 @@ data LayoutDecoration = HorizLine { _hlineCol :: !Col + , _hlineWhichQuad :: !WhichQuad -- align to which quad , _hlineVAlign :: !VAlign , _hlineVPos :: !Double , _hlineLineWidth :: !Double @@ -196,8 +231,8 @@ renderLayoutDecoration :: AbsBox -> LayoutDecoration -> IO () renderLayoutDecoration absbox decor = case decor of - HorizLine col valign vpos lwidth -> do - let Quad (x1,y1) (x2,y2) = absboxBoundingQuad absbox + HorizLine col whichquad valign vpos lwidth -> do + let Quad (x1,y1) (x2,y2) = absboxSelectQuad whichquad absbox let y = case valign of AlignTop -> y1 - vpos AlignBottom -> y2 - vpos @@ -233,7 +268,7 @@ defaultCfg :: Cfg defaultCfg = Cfg - { _currentSize = SizeIndex 0 + { _currentSize = NormalSize , _currentStyle = Regular , _currentColor = Col 0 0 0 } @@ -252,11 +287,12 @@ initialCfg = defaultCfg - sizeHeight :: SizeIndex -> Int - sizeHeight = calculateSizeHeight height + sizeXHeight, sizeYHeight :: SizeIndex -> Int + sizeXHeight = calculateSizeXHeight height + sizeYHeight = calculateSizeYHeight height - fsizeHeight :: SizeIndex -> Double - fsizeHeight = fromIntegral . sizeHeight + fsizeYHeight :: SizeIndex -> Double + fsizeYHeight = fromIntegral . sizeYHeight relativePlacement :: ([Box] -> (Box,[AbsBox])) -> Cfg -> [Document ident] -> IO (Box, Layout ident style) relativePlacement place !cfg docs = case docs of @@ -279,22 +315,22 @@ Decorated decor doc -> do (box,lout) <- go cfg doc - let col = _currentColor cfg - ht = fsizeHeight (_currentSize cfg) + let col = _currentColor cfg + ht = fsizeYHeight (_currentSize cfg) lwidth = horizLineWidth * ht ldecor = case decor of - Underline -> HorizLine col AlignBottom (underlinePos * ht) lwidth - Overline -> HorizLine col AlignTop (overlinePos * ht) lwidth - StrikeThrough -> HorizLine col AlignBottom (strikeThroughPos * ht) lwidth + Underline -> HorizLine col BoundingQuad AlignBottom (underlinePos * ht) lwidth + Overline -> HorizLine col BoundingQuad AlignTop (overlinePos * ht) lwidth + StrikeThrough -> HorizLine col InnerQuad AlignBottom (strikeThroughPos * ht) lwidth return (box, LoutDecor ldecor lout) SubSupScript subsup doc -> do let (doc1,doc2) = subSupDocs subsup (box0,lout0) <- go cfg doc - let cfg' = cfg { _currentSize = succSizeIndex (_currentSize cfg) } + let cfg' = cfg { _currentSize = scriptSuccSizeIndex (_currentSize cfg) } (box1,lout1) <- go cfg' doc1 (box2,lout2) <- go cfg' doc2 - let ht = fsizeHeight (_currentSize cfg) + let ht = fsizeYHeight (_currentSize cfg) ofs1 = - subPos * ht ofs2 = - supPos * ht let (box,(pos1,pos2)) = subSupScriptBox box0 (ofs1,box1) (ofs2,box2) @@ -304,19 +340,70 @@ AboveBelow aboveBelow doc -> do let (doc1,doc2) = aboveBelowDocs aboveBelow (box0,lout0) <- go cfg doc - let cfg' = cfg { _currentSize = succSizeIndex (_currentSize cfg) } + let cfg' = cfg { _currentSize = scriptSuccSizeIndex (_currentSize cfg) } (box1,lout1) <- go cfg' doc1 (box2,lout2) <- go cfg' doc2 - let ht = fsizeHeight (_currentSize cfg) + let ht = fsizeYHeight (_currentSize cfg) ofs1 = Pos 0 (- abovePos * ht) ofs2 = Pos 0 (- belowPos * ht) let (box,(pos1,pos2)) = aboveBelowBox box0 (ofs1,box1) (ofs2,box2) lout = LoutGroup box [ lout0, translate pos1 lout1 , translate pos2 lout2 ] return (box,lout) + -- TODO: optimized this (docs are computed twice now!) + Delimited delim docs -> do + let h = sizeYHeight (_currentSize cfg) + (box0,_) <- go cfg (HorzCat AlignBottom docs) + let outer = boxOuterQuad box0 + tgt = quadHeight outer + vofs = 0 + -- print box0 + let left = finalDelim' vofs (Height h) delim tgt LeftDelim + right = finalDelim' vofs (Height h) delim tgt RightDelim + mid = finalDelim' vofs (Height h) VertSingle tgt RightDelim + + -- go cfg $ HorzCat AlignBottom $ left : intersperse mid docs ++ right : [] + + (bl,loutl) <- go cfg left + (bm,loutm) <- go cfg mid + (br,loutr) <- go cfg right + (boxes,louts) <- unzip <$> mapM (go cfg) docs + let (box,poslist) = delimiterBox (bl,bm,br) boxes + lout = LoutGroup box + $ zipWith translate poslist + $ (loutl : intersperse loutm louts ++ loutr : []) + return (box,lout) + Realign which doc -> do (box , lout) <- go cfg doc - let box' = realignBox which box + let (ofs, box') = realignBox which box + return (box', reboxLayout box' $ translateLayout ofs $ lout) + + Fraction drawline doc1 doc2 -> do + let csiz = _currentSize cfg + let cfg' = cfg { _currentSize = fracSuccSizeIndex csiz } + mbtrim = case csiz of { NormalSize -> id ; _ -> Trim } + (box1,lout1) <- go cfg' $ mbtrim doc1 + (box2,lout2) <- go cfg' $ mbtrim doc2 + let (w1,h1) = quadSize $ boxBoundingQuad box1 -- boxOuterQuad box1 + (w2,h2) = quadSize $ boxBoundingQuad box2 -- boxOuterQuad box2 + w = max w1 w2 + let ht = fsizeYHeight (_currentSize cfg) + ymarg = (ht * fracYMargin) + let (box,(pos1,pos2)) = fractionBox ymarg box1 box2 + lout0 = LoutGroup box [ translate pos1 lout1 , translate pos2 lout2 ] + let col = _currentColor cfg + lwidth = horizLineWidth * ht + let yofs = - fracLinePos * ht + pos = Pos 0 yofs + let lout = case drawline of + False -> lout0 + True -> LoutDecor (HorizLine col InnerQuad AlignBottom (0) lwidth) lout0 + return (shiftBox pos box, translateLayout pos lout) + + Trim doc -> do + (box , lout) <- go cfg doc + let box' = trimBox box return (box', reboxLayout box' lout) AddMargin margin doc -> do @@ -326,6 +413,15 @@ box' = Box siz outer' bound gap' return (box' , reboxLayout box' lout) + RePosition pos doc -> do + (box , lout) <- go cfg doc + return (shiftBox pos box, translateLayout pos lout) + + UnsafeResize (x,y) doc -> do + let sidx = _currentSize cfg + cfg' = cfg { _currentSize = CustomSize (x,y) sidx } + go cfg' doc + Identified uid doc -> do (box, lout) <- go cfg doc return (box, LoutIdent uid lout) @@ -333,7 +429,7 @@ Symbol char -> do let Cfg size style0 col = cfg style = styleMap style0 - mfg@(MFG ftex bufloc) <- lkpMultiFont multifont (sizeHeight size) style char + mfg@(MFG ftex bufloc) <- lkpMultiFont' multifont (sizeXHeight size, sizeYHeight size) style char let relbox = mfgRelBox mfg lout = LoutGlyph (Pos 0 0) style col char mfg return (relbox, lout)
src/Graphics/Rendering/MiniTypeset/MultiFont.hs view
@@ -100,13 +100,17 @@ Nothing -> Nothing Just sub -> IntMap.lookup j sub -mfAddNewFontTex :: Ord fontfile => MultiFont fontfile style -> (fontfile,Int) -> IO () -mfAddNewFontTex mf (ffile,height) = do +encodeXYHeight :: (Int,Int) -> Int +encodeXYHeight (xheight,yheight) = yheight * 32768 + xheight + +mfAddNewFontTex :: Ord fontfile => MultiFont fontfile style -> (fontfile,(Int,Int)) -> IO () +mfAddNewFontTex mf (ffile,(xheight,yheight)) = do old_table <- readIORef (_mfFontTexs mf) let fpath = (_ufcFontFiles $ _mfUserConfig mf) ffile font <- loadFontFile fpath - ftex <- newFontTexture' font (fromIntegral height) (takeFileName fpath) (stdFontTextureSize height) (mfLineGapFactor mf) - let new_table = mapInsert (IntMap.singleton height ftex) (IntMap.insert height ftex) ffile old_table + let idx = encodeXYHeight (xheight,yheight) + ftex <- newFontTexture' font (fromIntegral xheight, fromIntegral yheight) (takeFileName fpath) (stdFontTextureSize yheight) (mfLineGapFactor mf) + let new_table = mapInsert (IntMap.singleton idx ftex) (IntMap.insert idx ftex) ffile old_table writeIORef (_mfFontTexs mf) new_table -------------------------------------------------------------------------------- @@ -120,27 +124,32 @@ mfgLineGapFactor (MFG ftex _) = _ftexLGapFactor ftex {- -mbLkpMultiFont :: Ord fontfile => MultiFont fontfile style -> Int -> style -> Char -> IO (Maybe MultiFontGlyph) -mbLkpMultiFont multifont height style char = do +mbLkpMultiFont' :: Ord fontfile => MultiFont fontfile style -> (Int,Int) -> style -> Char -> IO (Maybe MultiFontGlyph) +mbLkpMultiFont' multifont xyheight style char = do table <- readIORef (_mfFontTexs multifont) let fontfile = mfCharMap multifont style char - case mapIntLookup fontfile height table of + let idx = encodeXYHeight xyheight + case mapIntLookup fontfile idx table of Nothing -> do - mfAddNewFontTex multifont (fontfile,height) - mbLkpMultiFont multifont height style char + mfAddNewFontTex multifont (fontfile,xyheight) + mbLkpMultiFont multifont idx style char Just ftex -> do mbloc <- mbLookupFontTexture ftex char return $ liftM (\loc -> (MFG ftex loc)) mbloc -} lkpMultiFont :: Ord fontfile => MultiFont fontfile style -> Int -> style -> Char -> IO MultiFontGlyph -lkpMultiFont multifont height style char = do +lkpMultiFont multifont height style char = lkpMultiFont' multifont (height,height) style char + +lkpMultiFont' :: Ord fontfile => MultiFont fontfile style -> (Int,Int) -> style -> Char -> IO MultiFontGlyph +lkpMultiFont' multifont xyheight style char = do table <- readIORef (_mfFontTexs multifont) let fontfile = mfCharMap multifont style char - case mapIntLookup fontfile height table of + let idx = encodeXYHeight xyheight + case mapIntLookup fontfile idx table of Nothing -> do - mfAddNewFontTex multifont (fontfile,height) - lkpMultiFont multifont height style char + mfAddNewFontTex multifont (fontfile,xyheight) + lkpMultiFont' multifont xyheight style char Just ftex -> do loc <- lookupFontTexture ftex char return $ MFG ftex loc
src/Graphics/Rendering/MiniTypeset/Render.hs view
@@ -62,6 +62,33 @@ renderBoundingBoxQuad = renderQuad . absboxBoundingQuad -------------------------------------------------------------------------------- +-- * Render box outlines + +renderQuadOutline :: Quad -> IO () +renderQuadOutline (Quad (x1,y1) (x2,y2)) = + renderPrimitive LineLoop $ do + vertex (Vertex2 x1 y1) + vertex (Vertex2 x2 y1) + vertex (Vertex2 x2 y2) + vertex (Vertex2 x1 y2) + +-- | Renders the outer box as a quad +renderOuterBoxOutline :: AbsBox -> IO () +renderOuterBoxOutline = renderQuadOutline . absboxOuterQuad + +-- | Renders the inner box as a quad +renderInnerBoxOutline :: AbsBox -> IO () +renderInnerBoxOutline = renderQuadOutline . absboxInnerQuad + +-- | Renders the gap quad (useful for debugging) +renderGapBoxOutline :: AbsBox -> IO () +renderGapBoxOutline = renderQuadOutline . absboxGapQuad + +-- | Renders the bounding box quad (useful for debugging) +renderBoundingBoxOutline :: AbsBox -> IO () +renderBoundingBoxOutline = renderQuadOutline . absboxBoundingQuad + +-------------------------------------------------------------------------------- -- * Render lines -- TODO: finetune line rendering (retina display, antialising, position hinting based on width, etc...)