module Data.Text.ParagraphLayout.Internal.RunSpec (spec) where import Data.Text (Text, empty, pack) import Data.Text.Glyphize (Direction (..), emptyFont) import Test.Hspec import Data.Text.ParagraphLayout.Internal.BiDiLevels import Data.Text.ParagraphLayout.Internal.BoxOptions import Data.Text.ParagraphLayout.Internal.LineHeight import Data.Text.ParagraphLayout.Internal.ResolvedBox import Data.Text.ParagraphLayout.Internal.ResolvedSpan import Data.Text.ParagraphLayout.Internal.Run import Data.Text.ParagraphLayout.Internal.TextOptions import Data.Text.ParagraphLayout.RunLengthEncoding import Data.Text.ParagraphLayout.TextData defaultBox :: Direction -> ResolvedBox () defaultBox dir = ResolvedBox () 0 (defaultTextOptions dir) defaultBoxOptions dir sampleSpan :: (Direction, String, Text, a) -> TextLevels -> ResolvedSpan () sampleSpan (dir, lang, text, _) levels = ResolvedSpan { spanUserData = () , spanIndex = 0 , spanOffsetInParagraph = 0 , spanText = text , spanTextOptions = (defaultTextOptions dir) { textFont = emptyFont , textLineHeight = Normal , textLanguage = lang } , spanBoxes = [defaultBox dir] , spanBiDiLevels = levels , spanLineBreaks = [] , spanCharacterBreaks = [] } allLTR :: TextLevels allLTR = TextLevels (repeat 0) 0 allRTL :: TextLevels allRTL = TextLevels (repeat 1) 1 levelsRLE :: [(Int, Level)] -> TextLevels levelsRLE rls = TextLevels (runLengthDecode rls) undefined spec :: Spec spec = do describe "spanToRuns" $ do it "handles span with no text" $ do let inputSpan = sampleSpan englishEmpty allLTR let runs = spanToRuns inputSpan runs `shouldBe` [ Run { runOffsetInSpan = 0 , runText = empty , runLevel = 0 , runDirection = DirLTR , runScript = Nothing , runHardBreak = False } ] it "handles Czech hello" $ do let inputSpan = sampleSpan czechHello allLTR let runs = spanToRuns inputSpan runs `shouldBe` [ Run { runOffsetInSpan = 0 , runText = spanText inputSpan , runLevel = 0 , runDirection = DirLTR , runScript = Just "Latn" , runHardBreak = False } ] it "handles Arabic hello" $ do let inputSpan = sampleSpan arabicHello allRTL let runs = spanToRuns inputSpan runs `shouldBe` [ Run { runOffsetInSpan = 0 , runText = spanText inputSpan , runLevel = 1 , runDirection = DirRTL , runScript = Just "Arab" , runHardBreak = False } ] it "handles Serbian with mixed script" $ do let inputSpan = sampleSpan serbianMixedScript allLTR let runs = spanToRuns inputSpan runs `shouldBe` [ Run -- TODO: We might want both parentheses in the same run. { runOffsetInSpan = 0 , runText = pack "Vikipedija (" , runLevel = 0 , runDirection = DirLTR , runScript = Just "Latn" , runHardBreak = False } , Run { runOffsetInSpan = 12 , runText = pack "Википедија)" , runLevel = 0 , runDirection = DirLTR , runScript = Just "Cyrl" , runHardBreak = False } ] it "handles mixed direction with base LTR" $ do let levels = levelsRLE [(7, 0), (3, 1), (6, 0)] let inputSpan = sampleSpan (mixedDirectionSimple DirLTR) levels let runs = spanToRuns inputSpan runs `shouldBe` [ Run { runOffsetInSpan = 0 , runText = pack "bahrain" , runLevel = 0 , runDirection = DirLTR , runScript = Just "Latn" , runHardBreak = False } , Run { runOffsetInSpan = 7 , runText = pack "مصر" , runLevel = 1 , runDirection = DirRTL , runScript = Just "Arab" , runHardBreak = False } , Run { runOffsetInSpan = 13 , runText = pack "kuwait" , runLevel = 0 , runDirection = DirLTR , runScript = Just "Latn" , runHardBreak = False } ] it "handles mixed direction with base RTL" $ do let levels = levelsRLE [(7, 2), (3, 1), (6, 2)] let inputSpan = sampleSpan (mixedDirectionSimple DirRTL) levels let runs = spanToRuns inputSpan runs `shouldBe` [ Run { runOffsetInSpan = 0 , runText = pack "bahrain" , runLevel = 2 , runDirection = DirLTR , runScript = Just "Latn" , runHardBreak = False } , Run { runOffsetInSpan = 7 , runText = pack "مصر" , runLevel = 1 , runDirection = DirRTL , runScript = Just "Arab" , runHardBreak = False } , Run { runOffsetInSpan = 13 , runText = pack "kuwait" , runLevel = 2 , runDirection = DirLTR , runScript = Just "Latn" , runHardBreak = False } ] it "handles Arabic text with English inside" $ do let levels = levelsRLE [(3, 1), (9, 2), (36, 1), (3, 2), (1, 1)] let inputSpan = sampleSpan arabicAroundEnglish levels let runs = spanToRuns inputSpan runs `shouldBe` [ Run { runOffsetInSpan = 0 , runText = pack "في " , runLevel = 1 , runDirection = DirRTL , runScript = Just "Arab" , runHardBreak = False } , Run { runOffsetInSpan = 5 , runText = pack "XHTML 1.0" , runLevel = 2 , runDirection = DirLTR , runScript = Just "Latn" , runHardBreak = False } , Run { runOffsetInSpan = 14 , runText = pack " يتم تحقيق ذلك بإضافة العنصر المضمن " , runLevel = 1 , runDirection = DirRTL , runScript = Just "Arab" , runHardBreak = False } , Run { runOffsetInSpan = 79 , runText = pack "bdo" , runLevel = 2 , runDirection = DirLTR , runScript = Just "Latn" , runHardBreak = False } , Run { runOffsetInSpan = 82 , runText = pack "." , runLevel = 1 , runDirection = DirRTL , runScript = Just "Zyyy" , runHardBreak = False } ] it "handles English text with Arabic inside" $ do let levels = levelsRLE [(13, 0), (18, 1), (11, 0)] let inputSpan = sampleSpan englishAroundArabic levels let runs = spanToRuns inputSpan runs `shouldBe` [ Run { runOffsetInSpan = 0 , runText = pack "The title is " , runLevel = 0 , runDirection = DirLTR , runScript = Just "Latn" , runHardBreak = False } , Run { runOffsetInSpan = 13 , runText = pack "مفتاح معايير الويب" , runLevel = 1 , runDirection = DirRTL , runScript = Just "Arab" , runHardBreak = False } , Run { runOffsetInSpan = 47 , runText = pack " in Arabic." , runLevel = 0 , runDirection = DirLTR , runScript = Just "Latn" , runHardBreak = False } ] -- Unrealistic example where text changes direction -- without changing script. it "handles script and direction changes" $ do let levels = levelsRLE [(4, 1), (4, 2), (8, 1), (4, 2), (3, 1)] let inputSpan = sampleSpan serbianMixedScript levels let runs = spanToRuns inputSpan runs `shouldBe` [ Run { runOffsetInSpan = 0 , runText = pack "Viki" , runLevel = 1 , runDirection = DirRTL , runScript = Just "Latn" , runHardBreak = False } -- direction change , Run { runOffsetInSpan = 4 , runText = pack "pedi" , runLevel = 2 , runDirection = DirLTR , runScript = Just "Latn" , runHardBreak = False } -- direction change , Run { runOffsetInSpan = 8 , runText = pack "ja (" , runLevel = 1 , runDirection = DirRTL , runScript = Just "Latn" , runHardBreak = False } -- script change , Run { runOffsetInSpan = 12 , runText = pack "Вики" , runLevel = 1 , runDirection = DirRTL , runScript = Just "Cyrl" , runHardBreak = False } -- direction change , Run { runOffsetInSpan = 20 , runText = pack "педи" , runLevel = 2 , runDirection = DirLTR , runScript = Just "Cyrl" , runHardBreak = False } -- direction change , Run { runOffsetInSpan = 28 , runText = pack "ја)" , runLevel = 1 , runDirection = DirRTL , runScript = Just "Cyrl" , runHardBreak = False } ]