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
}
]