diff options
-rw-r--r-- | src/css/layout.nim | 125 | ||||
-rw-r--r-- | test/layout/pre-preserves-initial-whitespace.expected | 4 | ||||
-rw-r--r-- | test/layout/pre-preserves-initial-whitespace.html | 4 |
3 files changed, 71 insertions, 62 deletions
diff --git a/src/css/layout.nim b/src/css/layout.nim index fee0423b..311f826a 100644 --- a/src/css/layout.nim +++ b/src/css/layout.nim @@ -499,6 +499,53 @@ proc flushMargins(bctx: var BlockContext; offsety: var LUnit) = bctx.marginTodo = Strut() bctx.positionFloats() +# Prepare the next line's initial width and available width. +# (If space on the left is excluded by floats, set the initial width to +# the end of that space. If space on the right is excluded, set the +# available width to that space.) +type InitLineFlag = enum + ilfRegular # set the line to inited, and flush floats. + ilfFloat # set the line to inited, but do not flush floats. + ilfAbsolute # set size, but allow further calls to override the state. + +proc initLine(fstate: var FlowState; flag = ilfRegular) = + if flag != ilfFloat: + #TODO ^ this should really be ilfRegular, but that summons another, + # much worse bug. + # In fact, absolute handling in the presence of floats has always + # been somewhat broken and should be fixed some time. + if flag != ilfAbsolute: + let poffsety = fstate.offset.y + fstate.bctx.flushMargins(fstate.offset.y) + # Don't forget to add it to intrinsic height... + fstate.intr.h += fstate.offset.y - poffsety + fstate.bctx.positionFloats() + if fstate.lbstate.init != lisUninited: + return + # we want to start from padding-left, but normally exclude padding + # from space. so we must offset available width with padding-left too + fstate.lbstate.availableWidth = fstate.space.w.u + fstate.padding.left + fstate.lbstate.size.w = fstate.padding.left + fstate.lbstate.init = lisNoExclusions + #TODO what if maxContent/minContent? + if fstate.bctx.exclusions.len > 0: + let bfcOffset = fstate.bfcOffset + let y = fstate.offset.y + bfcOffset.y + var left = bfcOffset.x + fstate.lbstate.size.w + var right = bfcOffset.x + fstate.lbstate.availableWidth + for ex in fstate.bctx.relevantExclusions: + if ex.offset.y <= y and y < ex.offset.y + ex.size.h: + fstate.lbstate.init = lisExclusions + if ex.t == FloatLeft: + left = ex.offset.x + ex.size.w + else: + right = ex.offset.x + fstate.lbstate.size.w = max(left - bfcOffset.x, fstate.lbstate.size.w) + fstate.lbstate.availableWidth = min(right - bfcOffset.x, + fstate.lbstate.availableWidth) + if flag == ilfAbsolute: + fstate.lbstate.init = lisUninited + # Whitespace between words func computeShift(fstate: FlowState; istate: InlineState): LUnit = if fstate.whitespacenum == 0: @@ -637,8 +684,7 @@ proc putAtom(lbstate: var LineBoxState; iastate: InlineAtomState) = if iastate.ibox.t == ibtText: iastate.ibox.runs.add(iastate.run) -proc addSpacing(fstate: var FlowState; width: LUnit; state: InlineState; - hang = false) = +proc addSpacing(fstate: var FlowState; width: LUnit; hang = false) = let ibox = fstate.whitespaceBox if ibox.runs.len == 0 or fstate.lbstate.iastates.len == 0 or (let orun = ibox.runs[^1]; orun != fstate.lbstate.iastates[^1].run): @@ -661,13 +707,14 @@ proc addSpacing(fstate: var FlowState; width: LUnit; state: InlineState; # it is written, but is not actually counted in the box's width. fstate.lbstate.size.w += width -proc flushWhitespace(fstate: var FlowState; state: InlineState; +proc flushWhitespace(fstate: var FlowState; istate: InlineState; hang = false) = - let shift = fstate.computeShift(state) + let shift = fstate.computeShift(istate) fstate.lbstate.charwidth += fstate.whitespacenum fstate.whitespacenum = 0 if shift > 0: - fstate.addSpacing(shift, state, hang) + fstate.initLine() + fstate.addSpacing(shift, hang) proc clearFloats(offsety: var LUnit; bctx: var BlockContext; bfcOffsety: LUnit; clear: CSSClear) = @@ -690,53 +737,6 @@ proc clearFloats(offsety: var LUnit; bctx: var BlockContext; bctx.clearIndex[FloatNone] = max(bctx.clearIndex[FloatNone], k) offsety = y - bfcOffsety -# Prepare the next line's initial width and available width. -# (If space on the left is excluded by floats, set the initial width to -# the end of that space. If space on the right is excluded, set the -# available width to that space.) -type InitLineFlag = enum - ilfRegular # set the line to inited, and flush floats. - ilfFloat # set the line to inited, but do not flush floats. - ilfAbsolute # set size, but allow further calls to override the state. - -proc initLine(fstate: var FlowState; flag = ilfRegular) = - if flag != ilfFloat: - #TODO ^ this should really be ilfRegular, but that summons another, - # much worse bug. - # In fact, absolute handling in the presence of floats has always - # been somewhat broken and should be fixed some time. - if flag != ilfAbsolute: - let poffsety = fstate.offset.y - fstate.bctx.flushMargins(fstate.offset.y) - # Don't forget to add it to intrinsic height... - fstate.intr.h += fstate.offset.y - poffsety - fstate.bctx.positionFloats() - if fstate.lbstate.init != lisUninited: - return - # we want to start from padding-left, but normally exclude padding - # from space. so we must offset available width with padding-left too - fstate.lbstate.availableWidth = fstate.space.w.u + fstate.padding.left - fstate.lbstate.size.w = fstate.padding.left - fstate.lbstate.init = lisNoExclusions - #TODO what if maxContent/minContent? - if fstate.bctx.exclusions.len > 0: - let bfcOffset = fstate.bfcOffset - let y = fstate.offset.y + bfcOffset.y - var left = bfcOffset.x + fstate.lbstate.size.w - var right = bfcOffset.x + fstate.lbstate.availableWidth - for ex in fstate.bctx.relevantExclusions: - if ex.offset.y <= y and y < ex.offset.y + ex.size.h: - fstate.lbstate.init = lisExclusions - if ex.t == FloatLeft: - left = ex.offset.x + ex.size.w - else: - right = ex.offset.x - fstate.lbstate.size.w = max(left - bfcOffset.x, fstate.lbstate.size.w) - fstate.lbstate.availableWidth = min(right - bfcOffset.x, - fstate.lbstate.availableWidth) - if flag == ilfAbsolute: - fstate.lbstate.init = lisUninited - proc initLineBoxState(fstate: FlowState): LineBoxState = let cellHeight = fstate.cellHeight.toLUnit() result = LineBoxState( @@ -747,7 +747,9 @@ proc initLineBoxState(fstate: FlowState): LineBoxState = proc finishLine(fstate: var FlowState; istate: var InlineState; wrap: bool; force = false; clear = ClearNone) = - if fstate.lbstate.iastates.len != 0 or force: + if fstate.lbstate.iastates.len != 0 or force or + fstate.whitespacenum != 0 and istate.ibox != nil and + istate.ibox.computed{"white-space"} in {WhitespacePre, WhitespacePreWrap}: fstate.initLine() let whitespace = istate.ibox.computed{"white-space"} if whitespace == WhitespacePre: @@ -869,7 +871,7 @@ proc addAtom(fstate: var FlowState; istate: var InlineState; shift = fstate.computeShift(istate) if iastate.size.w > 0 and iastate.size.h > 0 or iastate.ibox.t == ibtBox: if shift > 0: - fstate.addSpacing(shift, istate) + fstate.addSpacing(shift) if iastate.run != nil and fstate.lbstate.iastates.len > 0 and istate.ibox.runs.len > 0: let oiastate = addr fstate.lbstate.iastates[^1] @@ -1043,12 +1045,12 @@ proc layoutTextLoop(fstate: var FlowState; state: var InlineState; let shift = fstate.computeShift(state) fstate.lbstate.widthAfterWhitespace = fstate.lbstate.size.w + shift -proc layoutText(fstate: var FlowState; state: var InlineState; s: string) = - fstate.flushWhitespace(state) - fstate.newWord(state.ibox) - let transform = state.ibox.computed{"text-transform"} +proc layoutText(fstate: var FlowState; istate: var InlineState; s: string) = + fstate.flushWhitespace(istate) + fstate.newWord(istate.ibox) + let transform = istate.ibox.computed{"text-transform"} if transform == TextTransformNone: - fstate.layoutTextLoop(state, s) + fstate.layoutTextLoop(istate, s) else: let s = case transform of TextTransformCapitalize: s.capitalizeLU() @@ -1058,7 +1060,7 @@ proc layoutText(fstate: var FlowState; state: var InlineState; s: string) = of TextTransformFullSizeKana: s.fullsize() of TextTransformChaHalfWidth: s.halfwidth() else: "" - fstate.layoutTextLoop(state, s) + fstate.layoutTextLoop(istate, s) func spx(l: CSSLength; p: SizeConstraint; computed: CSSValues; padding: LUnit): LUnit = @@ -2877,8 +2879,7 @@ proc layoutRootBlock(lctx: LayoutContext; box: BlockBox; offset: Offset; # 1st pass: build tree #TODO ideally we should move this to layout and/or cascade. # (Anon box generation probably belongs in cascade, so that caching -# existing boxes becomes feasible. This would also allow things like -# creating a custom anonymous box tree for input and select multiple.) +# existing boxes becomes feasible.) type BlockBuilderContext = object diff --git a/test/layout/pre-preserves-initial-whitespace.expected b/test/layout/pre-preserves-initial-whitespace.expected new file mode 100644 index 00000000..e06221e2 --- /dev/null +++ b/test/layout/pre-preserves-initial-whitespace.expected @@ -0,0 +1,4 @@ + + test + +test diff --git a/test/layout/pre-preserves-initial-whitespace.html b/test/layout/pre-preserves-initial-whitespace.html new file mode 100644 index 00000000..64b41db1 --- /dev/null +++ b/test/layout/pre-preserves-initial-whitespace.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<pre> + <span>test</span> + <div>test</div> |