module Data.Text.ParagraphLayout.Internal.RunSpec (spec) where import Data.Text (Text, 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 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 allRTL :: TextLevels allRTL = TextLevels $ repeat 1 levelsRLE :: [(Int, Level)] -> TextLevels levelsRLE rls = TextLevels $ runLengthDecode rls 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` [] 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 = Just DirLTR , runScript = Just "Latn" } ] 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 = Just DirRTL , runScript = Just "Arab" } ] 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 = Just DirLTR , runScript = Just "Latn" } , Run { runOffsetInSpan = 12 , runText = pack "Википедија)" , runLevel = 0 , runDirection = Just DirLTR , runScript = Just "Cyrl" } ] 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 = Just DirLTR , runScript = Just "Latn" } , Run { runOffsetInSpan = 7 , runText = pack "مصر" , runLevel = 1 , runDirection = Just DirRTL , runScript = Just "Arab" } , Run { runOffsetInSpan = 13 , runText = pack "kuwait" , runLevel = 0 , runDirection = Just DirLTR , runScript = Just "Latn" } ] 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 = Just DirLTR , runScript = Just "Latn" } , Run { runOffsetInSpan = 7 , runText = pack "مصر" , runLevel = 1 , runDirection = Just DirRTL , runScript = Just "Arab" } , Run { runOffsetInSpan = 13 , runText = pack "kuwait" , runLevel = 2 , runDirection = Just DirLTR , runScript = Just "Latn" } ] 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 = Just DirRTL , runScript = Just "Arab" } , Run { runOffsetInSpan = 5 , runText = pack "XHTML 1.0" , runLevel = 2 , runDirection = Just DirLTR , runScript = Just "Latn" } , Run { runOffsetInSpan = 14 , runText = pack " يتم تحقيق ذلك بإضافة العنصر المضمن " , runLevel = 1 , runDirection = Just DirRTL , runScript = Just "Arab" } , Run { runOffsetInSpan = 79 , runText = pack "bdo" , runLevel = 2 , runDirection = Just DirLTR , runScript = Just "Latn" } , Run { runOffsetInSpan = 82 , runText = pack "." , runLevel = 1 , runDirection = Just DirRTL , runScript = Just "Zyyy" } ] 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 = Just DirLTR , runScript = Just "Latn" } , Run { runOffsetInSpan = 13 , runText = pack "مفتاح معايير الويب" , runLevel = 1 , runDirection = Just DirRTL , runScript = Just "Arab" } , Run { runOffsetInSpan = 47 , runText = pack " in Arabic." , runLevel = 0 , runDirection = Just DirLTR , runScript = Just "Latn" } ] -- 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 = Just DirRTL , runScript = Just "Latn" } -- direction change , Run { runOffsetInSpan = 4 , runText = pack "pedi" , runLevel = 2 , runDirection = Just DirLTR , runScript = Just "Latn" } -- direction change , Run { runOffsetInSpan = 8 , runText = pack "ja (" , runLevel = 1 , runDirection = Just DirRTL , runScript = Just "Latn" } -- script change , Run { runOffsetInSpan = 12 , runText = pack "Вики" , runLevel = 1 , runDirection = Just DirRTL , runScript = Just "Cyrl" } -- direction change , Run { runOffsetInSpan = 20 , runText = pack "педи" , runLevel = 2 , runDirection = Just DirLTR , runScript = Just "Cyrl" } -- direction change , Run { runOffsetInSpan = 28 , runText = pack "ја)" , runLevel = 1 , runDirection = Just DirRTL , runScript = Just "Cyrl" } ]