From 31b3de038b0d395c6ba188738f757c68165025a6 Mon Sep 17 00:00:00 2001 From: Jaro Date: Thu, 23 Feb 2023 12:30:35 +0100 Subject: [PATCH] Upgrade Fragment to contain pen position. --- .golden/czechHelloParagraph/golden | 4 +-- .golden/mixedLanguageLTRParagraph/golden | 8 ++--- balkon.cabal | 1 + src/Data/Text/ParagraphLayout/Fragment.hs | 39 +++++++++++++++++++++ src/Data/Text/ParagraphLayout/Plain.hs | 38 +++----------------- test/Data/Text/ParagraphLayout/PlainSpec.hs | 18 ++++++---- 6 files changed, 63 insertions(+), 45 deletions(-) create mode 100644 src/Data/Text/ParagraphLayout/Fragment.hs diff --git a/.golden/czechHelloParagraph/golden b/.golden/czechHelloParagraph/golden index f6145c0..009d0e6 100644 --- a/.golden/czechHelloParagraph/golden +++ b/.golden/czechHelloParagraph/golden @@ -1,5 +1,5 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 5274, y_size = 0}, spanLayouts = [ - SpanLayout [(Rect {x_origin = 0, y_origin = 0, x_size = 5274, y_size = 0}, + SpanLayout [Fragment {fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 5274, y_size = 0}, fragmentPen = (0,0), fragmentGlyphs = [(GlyphInfo {codepoint = 36, cluster = 0, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 663, y_advance = 0, x_offset = 0, y_offset = 0}), (GlyphInfo {codepoint = 75, cluster = 1, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 571, y_advance = 0, x_offset = 0, y_offset = 0}), (GlyphInfo {codepoint = 82, cluster = 2, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 590, y_advance = 0, x_offset = 0, y_offset = 0}), @@ -12,5 +12,5 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 5274 (GlyphInfo {codepoint = 87, cluster = 10, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 392, y_advance = 0, x_offset = 0, y_offset = 0}), (GlyphInfo {codepoint = 72, cluster = 11, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}), (GlyphInfo {codepoint = 4, cluster = 12, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 276, y_advance = 0, x_offset = 0, y_offset = 0})] - )] + }] ]} diff --git a/.golden/mixedLanguageLTRParagraph/golden b/.golden/mixedLanguageLTRParagraph/golden index a20caf3..f84c1f9 100644 --- a/.golden/mixedLanguageLTRParagraph/golden +++ b/.golden/mixedLanguageLTRParagraph/golden @@ -1,5 +1,5 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 6113, y_size = 0}, spanLayouts = [ - SpanLayout [(Rect {x_origin = 0, y_origin = 0, x_size = 4837, y_size = 0}, + SpanLayout [Fragment {fragmentRect = Rect {x_origin = 0, y_origin = 0, x_size = 4837, y_size = 0}, fragmentPen = (0,0), fragmentGlyphs = [(GlyphInfo {codepoint = 77, cluster = 4, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 253, y_advance = 0, x_offset = 0, y_offset = 0}), (GlyphInfo {codepoint = 86, cluster = 5, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 446, y_advance = 0, x_offset = 0, y_offset = 0}), (GlyphInfo {codepoint = 72, cluster = 6, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 559, y_advance = 0, x_offset = 0, y_offset = 0}), @@ -11,10 +11,10 @@ ParagraphLayout {paragraphRect = Rect {x_origin = 0, y_origin = 0, x_size = 6113 (GlyphInfo {codepoint = 92, cluster = 12, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 497, y_advance = 0, x_offset = 0, y_offset = 0}), (GlyphInfo {codepoint = 15, cluster = 13, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 246, y_advance = 0, x_offset = 0, y_offset = 0}), (GlyphInfo {codepoint = 3, cluster = 14, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 231, y_advance = 0, x_offset = 0, y_offset = 0})] - )], - SpanLayout [(Rect {x_origin = 4837, y_origin = 0, x_size = 1276, y_size = 0}, + }], + SpanLayout [Fragment {fragmentRect = Rect {x_origin = 4837, y_origin = 0, x_size = 1276, y_size = 0}, fragmentPen = (0,0), fragmentGlyphs = [(GlyphInfo {codepoint = 0, cluster = 15, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 500, y_advance = 0, x_offset = 0, y_offset = 0}), (GlyphInfo {codepoint = 0, cluster = 18, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 500, y_advance = 0, x_offset = 0, y_offset = 0}), (GlyphInfo {codepoint = 4, cluster = 21, unsafeToBreak = False, unsafeToConcat = False, safeToInsertTatweel = False},GlyphPos {x_advance = 276, y_advance = 0, x_offset = 0, y_offset = 0})] - )] + }] ]} diff --git a/balkon.cabal b/balkon.cabal index 2475a4a..3ede50d 100644 --- a/balkon.cabal +++ b/balkon.cabal @@ -97,6 +97,7 @@ library -- Modules exported by the library. exposed-modules: Data.Text.ParagraphLayout, + Data.Text.ParagraphLayout.Fragment, Data.Text.ParagraphLayout.Plain, Data.Text.ParagraphLayout.Rect, Data.Text.ParagraphLayout.ResolvedSpan, diff --git a/src/Data/Text/ParagraphLayout/Fragment.hs b/src/Data/Text/ParagraphLayout/Fragment.hs new file mode 100644 index 0000000..d774697 --- /dev/null +++ b/src/Data/Text/ParagraphLayout/Fragment.hs @@ -0,0 +1,39 @@ +module Data.Text.ParagraphLayout.Fragment (Fragment(..)) +where + +import Data.Int (Int32) +import Data.Text.Glyphize (GlyphInfo, GlyphPos) + +import Data.Text.ParagraphLayout.Rect + +-- | Box fragment or fragment (CSS3), except that continuous text even within +-- one line can be split into multiple fragments because of spans or changes in +-- script. +data Fragment = Fragment + { fragmentRect :: Rect Int32 + -- ^ Physical position of the fragment within the paragraph, calculated + -- using all glyph advances in this fragment and the calculated line height. + -- + -- This is the space that the glyphs "take up" and is probably what you + -- want to use for detecting position-based events such as mouse clicks. + -- + -- Beware that actual glyphs will not be drawn exactly to the borders of + -- this rectangle -- they may be offset inwards and they can also extend + -- outwards! + -- + -- These are not the typographic bounding boxes that you use for determining + -- the area to draw on -- you need FreeType or a similar library for that. + -- + -- The origin coordinates are relative to the paragraph. + -- + -- The sizes can be positive or negative, depending on the text direction. + -- + -- X coordinates increase from left to right. + -- Y coordinates increase from bottom to top. + , fragmentPen :: (Int32, Int32) + -- ^ Coordinates of the initial pen position, from which the first glyph + -- should be drawn. That glyph's `x_advance` or `y_advance` are then used + -- to move the pen position for the next glyph. + , fragmentGlyphs :: [(GlyphInfo, GlyphPos)] + } + deriving (Eq, Read, Show) diff --git a/src/Data/Text/ParagraphLayout/Plain.hs b/src/Data/Text/ParagraphLayout/Plain.hs index ad49e86..e643a13 100644 --- a/src/Data/Text/ParagraphLayout/Plain.hs +++ b/src/Data/Text/ParagraphLayout/Plain.hs @@ -28,7 +28,6 @@ import Data.Text.Glyphize (Buffer(..) ,ContentType(ContentTypeUnicode) ,Font - ,GlyphInfo ,GlyphPos(x_advance, y_advance) ,defaultBuffer ,shape @@ -36,6 +35,7 @@ import Data.Text.Glyphize import Data.Text.Internal (Text(Text)) import qualified Data.Text.Lazy as Lazy +import Data.Text.ParagraphLayout.Fragment import Data.Text.ParagraphLayout.Rect import qualified Data.Text.ParagraphLayout.ResolvedSpan as RS import Data.Text.ParagraphLayout.Run @@ -91,36 +91,6 @@ data ParagraphLayout = ParagraphLayout data SpanLayout = SpanLayout [Fragment] deriving (Eq, Read, Show) --- | Box fragment or fragment (CSS3), except that continuous text even within --- one line can be split into multiple fragments because of spans or changes in --- script. -type Fragment = - ( Rect Int32 - -- ^ Physical position of the fragment within the paragraph, calculated - -- using all glyph advances in this fragment and the calculated line height. - -- - -- This is the space that the glyphs "take up" and is probably what you - -- want to use for detecting position-based events such as mouse clicks. - -- - -- Beware that actual glyphs will not be drawn exactly to the borders of - -- this rectangle -- they may be offset inwards and they can also extend - -- outwards! - -- - -- These are not the typographic bounding boxes that you use for determining - -- the area to draw on -- you need FreeType or a similar library for that. - -- - -- The origin coordinates are relative to the paragraph. - -- - -- The sizes can be positive or negative, depending on the text direction. - -- - -- X coordinates increase from left to right. - -- Y coordinates increase from bottom to top. - , [(GlyphInfo, GlyphPos)] - ) - -fragmentRect :: Fragment -> Rect Int32 -fragmentRect = fst - spanRects :: SpanLayout -> [Rect Int32] spanRects (SpanLayout frags) = map fragmentRect frags @@ -157,8 +127,9 @@ layoutPlain paragraph = ParagraphLayout pRect arrangedLayouts layoutSpan :: RS.ResolvedSpan -> SpanLayout layoutSpan rs = SpanLayout (map layoutRun $ spanToRuns rs) +-- TODO: Calculate line height and pen position. layoutRun :: Run -> Fragment -layoutRun run = (rect, glyphs) +layoutRun run = Fragment rect (0, 0) glyphs where rs = runOriginalSpan run rect = containGlyphs $ map snd $ glyphs @@ -219,7 +190,8 @@ arrangeFragmentsH currentX frags = mapAccumL arrangeFragmentH currentX frags -- | Set the horizontal offset of the given box -- and return the x coordinate of its other side for continuation. arrangeFragmentH :: Int32 -> Fragment -> (Int32, Fragment) -arrangeFragmentH currentX (rect, glyphs) = (nextX, (newRect, glyphs)) +arrangeFragmentH currentX frag = (nextX, frag { fragmentRect = newRect }) where + rect = fragmentRect frag nextX = currentX + x_size rect newRect = rect { x_origin = currentX } diff --git a/test/Data/Text/ParagraphLayout/PlainSpec.hs b/test/Data/Text/ParagraphLayout/PlainSpec.hs index 8500b51..f411e78 100644 --- a/test/Data/Text/ParagraphLayout/PlainSpec.hs +++ b/test/Data/Text/ParagraphLayout/PlainSpec.hs @@ -7,6 +7,7 @@ import Test.Hspec import Test.Hspec.Golden import System.FilePath (()) import Data.Text.ParagraphLayout.FontLoader +import Data.Text.ParagraphLayout.Fragment import Data.Text.ParagraphLayout.ParagraphData import Data.Text.ParagraphLayout.Plain @@ -23,23 +24,28 @@ prettyShow (ParagraphLayout pr sls) = showParagraphLayout where , newline ] showSpanLayouts = concat $ intersperse commaNewline $ map showSpanLayout sls - showSpanLayout (SpanLayout boxes) = concat + showSpanLayout (SpanLayout frags) = concat [ indent1 , "SpanLayout [" - , concat $ map showBox boxes + , concat $ map showFrag frags , "]" ] - showBox (r, glyphs) = concat - [ "(" + showFrag (Fragment r pen glyphs) = concat + [ "Fragment {fragmentRect = " , show r - , commaNewline + , ", " + , "fragmentPen = " + , show pen + , ", " + , "fragmentGlyphs =" + , newline , indent2 , "[" , showGlyphs glyphs , "]" , newline , indent1 - , ")" + , "}" ] showGlyphs = concat . intersperse (commaNewline ++ indent2) . map show indent1 = " " -- 2.30.2