module Data.Text.ParagraphLayout.Internal.Plain.ParagraphLayout
( ParagraphLayout (..)
, appendFragments
, emptyParagraphLayout
, filterFragments
, mapFragments
, paragraphFragments
, paragraphLayout
, shapedRuns
)
where
import Data.Int (Int32)
import Data.Text.ParagraphLayout.Internal.Fragment
import Data.Text.ParagraphLayout.Internal.LineNumbers
import Data.Text.ParagraphLayout.Internal.LinePagination
import Data.Text.ParagraphLayout.Internal.ParagraphExtents
import Data.Text.ParagraphLayout.Internal.Rect
import Data.Text.ParagraphLayout.Internal.Span
-- | The resulting layout of the whole paragraph.
data ParagraphLayout d = ParagraphLayout
{ paragraphRect :: Rect Int32
-- ^ The containing block (CSS3).
, spanLayouts :: [SpanLayout d]
}
deriving (Eq, Read, Show)
instance LineNumbers (ParagraphLayout d) where
lineNumbersWithDuplication pl = map fragmentLine $ paragraphFragments pl
instance LineHeight (ParagraphLayout d) where
lineHeight pl = height $ paragraphRect pl
-- | Wrap the given `SpanLayout`s and compute their containing rectangle.
paragraphLayout :: [SpanLayout d] -> ParagraphLayout d
paragraphLayout sls = ParagraphLayout pRect sls
where pRect = containRects $ concat $ map spanRects sls
-- | A `ParagraphLayout` with an infinite number of empty spans.
-- Useful as an identity element for `appendFragments`.
emptyParagraphLayout :: ParagraphLayout d
emptyParagraphLayout = ParagraphLayout emptyRect $ repeat (SpanLayout [])
-- | Remove fragments that do not match the given predicate.
--
-- The containing rectangle will be recalculated.
filterFragments :: (Fragment d -> Bool) -> ParagraphLayout d ->
ParagraphLayout d
filterFragments fragPred (ParagraphLayout _ sls) =
paragraphLayout sls'
where
sls' = map slMapFunc sls
slMapFunc (SpanLayout frags) = SpanLayout (filter fragPred frags)
-- | Run a mapping function over each fragment inside a `ParagraphLayout`.
--
-- The containing rectangle will be recalculated.
mapFragments :: (Fragment d -> Fragment d) -> ParagraphLayout d ->
ParagraphLayout d
mapFragments fragMapFunc (ParagraphLayout _ sls) =
paragraphLayout sls'
where
sls' = map slMapFunc sls
slMapFunc (SpanLayout frags) = SpanLayout (map fragMapFunc frags)
-- | Combine fragments from two `ParagraphLayout`s.
--
-- The containing rectangle will be recalculated.
appendFragments :: ParagraphLayout d -> ParagraphLayout d -> ParagraphLayout d
appendFragments pla plb = paragraphLayout sls'
where
sls' = zipWith zipFunc slsa slsb
slsa = spanLayouts pla
slsb = spanLayouts plb
zipFunc (SpanLayout fa) (SpanLayout fb) = SpanLayout (fa ++ fb)
-- | Return all fragments of shaped text in one flat list,
-- discarding information about their associated spans.
paragraphFragments :: ParagraphLayout d -> [Fragment d]
paragraphFragments pl = concat $ map spanFragments $ spanLayouts pl
-- | Return all non-empty shaped runs in the paragraph.
shapedRuns :: ParagraphLayout d -> [ShapedRun]
shapedRuns pl = map shapedRun $ filter hasGlyphs $ paragraphFragments pl
where
hasGlyphs = not . null . fragmentGlyphs