@@ 4,9 4,11 @@ module Data.Text.ParagraphLayout.Rich.ParagraphData
, loremIpsumParagraph
, mixedSizesParagraph
, nestedBoxesParagraph
+ , softBreakParagraph
)
where
+import Data.Int (Int32)
import Data.Text (pack)
import Data.Text.Glyphize (Direction (DirLTR, DirRTL), Font)
@@ 121,3 123,21 @@ nestedBoxesParagraph font = constructParagraph
(pack "suffix")
where
t = tLTR { textFont = font, textLanguage = "en" }
+
+softBreakParagraph :: Int32 -> Font -> ParagraphOptions -> Paragraph String
+softBreakParagraph spacing font = constructParagraph
+ (pack "prefix")
+ (rootBox t
+ [ text "text1" "Lorem "
+ , text "text2" "ipsum "
+ , box "box2" b t
+ [ text "text3" "dolor "
+ , text "text4" "sit "
+ , text "text5" "amet,"
+ ]
+ ]
+ )
+ (pack "suffix")
+ where
+ b = b_ { boxSpacing = BoxSpacingLeftRight spacing spacing }
+ t = tLTR { textFont = font, textLanguage = "en" }
@@ 1,5 1,7 @@
module Data.Text.ParagraphLayout.RichSpec (spec) where
+import Data.Int (Int32)
+
import Test.Hspec
import System.FilePath ((</>))
import Data.Text.ParagraphLayout
@@ 7,9 9,14 @@ import Data.Text.ParagraphLayout.FontLoader
import Data.Text.ParagraphLayout.Internal.Paginable (paginateAll)
import Data.Text.ParagraphLayout.PrettyShow
import Data.Text.ParagraphLayout.PrettyShow.Golden
+import Data.Text.ParagraphLayout.Rect
import Data.Text.ParagraphLayout.Rich
import Data.Text.ParagraphLayout.Rich.ParagraphData
+fragmentRects :: ParagraphLayout d -> [(d, Rect Int32)]
+fragmentRects p = map toItem $ paragraphFragments p
+ where toItem (Fragment { fragmentUserData = d, fragmentRect = r }) = (d, r)
+
spec :: Spec
spec = do
@@ 46,6 53,52 @@ spec = do
let result = layoutRich input
result `shouldBeGolden` "hardBoxBreakLTR"
+ it "breaks line early if box spacing does not fit" $ do
+ let lineH = -1121
+ let lineY n = lineH * (n - 1)
+ let wordAdvancesWithSpace = [3134, 2954, 2659, 1332, 2601]
+ let spaceAdvance = 231
+ let wordW n = wordAdvancesWithSpace !! (n - 1)
+ let wordW_ n = wordW n - spaceAdvance
+ let originX = 0
+ let wordX n =
+ originX + (sum $ take (n - 1) wordAdvancesWithSpace)
+ let endX = originX + (sum wordAdvancesWithSpace)
+ -- A paragraph exactly wide enough to fit the whole text.
+ let opts = defaultParagraphOptions { paragraphMaxWidth = endX }
+ -- Small spacing that should push one word onto the next line.
+ let s = 5
+ -- Large spacing that should push two words onto the next line.
+ let s' = wordW 5 + spaceAdvance + 1
+ let inputNoSpacing = softBreakParagraph 0 font opts
+ let inputSmallSpacing = softBreakParagraph s font opts
+ let inputLargeSpacing = softBreakParagraph s' font opts
+ let resultNoSpacing = layoutRich inputNoSpacing
+ let resultSmallSpacing = layoutRich inputSmallSpacing
+ let resultLargeSpacing = layoutRich inputLargeSpacing
+ fragmentRects resultNoSpacing `shouldBe`
+ [ ("text1", Rect (wordX 1) (lineY 1) (wordW 1) lineH)
+ , ("text2", Rect (wordX 2) (lineY 1) (wordW 2) lineH)
+ , ("text3", Rect (wordX 3) (lineY 1) (wordW 3) lineH)
+ , ("text4", Rect (wordX 4) (lineY 1) (wordW 4) lineH)
+ , ("text5", Rect (wordX 5) (lineY 1) (wordW 5) lineH)
+ ]
+ fragmentRects resultSmallSpacing `shouldBe`
+ [ ("text1", Rect (wordX 1) (lineY 1) (wordW 1) lineH)
+ , ("text2", Rect (wordX 2) (lineY 1) (wordW 2) lineH)
+ , ("text3", Rect (wordX 3 + s) (lineY 1) (wordW 3) lineH)
+ , ("text4", Rect (wordX 4 + s) (lineY 1) (wordW_ 4) lineH)
+ , ("text5", Rect originX (lineY 2) (wordW 5) lineH)
+ ]
+ fragmentRects resultLargeSpacing `shouldBe`
+ [ ("text1", Rect (wordX 1) (lineY 1) (wordW 1) lineH)
+ , ("text2", Rect (wordX 2) (lineY 1) (wordW 2) lineH)
+ , ("text3", Rect (wordX 3 + s') (lineY 1) (wordW_ 3) lineH)
+ , ("text4", Rect originX (lineY 2) (wordW 4) lineH)
+ , ("text5",
+ Rect (originX + wordW 4) (lineY 2) (wordW 5) lineH)
+ ]
+
describe "with Arabic font" $ do
font <- runIO $ loadFont arabicFont 0 testingOptions