diff options
author | bptato <nincsnevem662@gmail.com> | 2024-02-28 01:50:18 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-02-28 01:50:48 +0100 |
commit | 11267020c1bb85d9c27548d13182f889e5444909 (patch) | |
tree | a63d35e66ba85dcf87eb21581a00c62a4ca7bb58 /src/layout | |
parent | cc8d4b154aed19689aedae904cfde2832a3a165c (diff) | |
download | chawan-11267020c1bb85d9c27548d13182f889e5444909.tar.gz |
layout: improve/simplify line box error correction
The previous retrofitting of the old renderdocument error correction usually worked, but it still had a horrible flaw in that it assumed that all line boxes are of equal height. So if error was lower for some line than another, it would move *all* lines by a somewhat lower error, and that resulted in overlapping lines. Now we do something much simpler: in flushLine, round each line's height downwards before moving on to the next line. This gets rid of any blanks inbetween lines, and also works much better with cleared floats.
Diffstat (limited to 'src/layout')
-rw-r--r-- | src/layout/box.nim | 5 | ||||
-rw-r--r-- | src/layout/engine.nim | 48 |
2 files changed, 17 insertions, 36 deletions
diff --git a/src/layout/box.nim b/src/layout/box.nim index b4b4e030..930ffa90 100644 --- a/src/layout/box.nim +++ b/src/layout/box.nim @@ -25,11 +25,6 @@ type of INLINE_BLOCK: innerbox*: BlockBox - LineBox* = ref object - atoms*: seq[InlineAtom] - offsety*: LayoutUnit - size*: Size - RootInlineFragment* = ref object # offset relative to parent offset*: Offset diff --git a/src/layout/engine.nim b/src/layout/engine.nim index 0377dbb0..c76c4be5 100644 --- a/src/layout/engine.nim +++ b/src/layout/engine.nim @@ -196,6 +196,11 @@ type # Set at the end of layoutText. It helps determine the beginning of the # next inline fragment. widthAfterWhitespace: LayoutUnit + offsety: LayoutUnit + + LineBox = ref object + atoms: seq[InlineAtom] + size: Size InlineAtomState = object vertalign: CSSVerticalAlign @@ -221,7 +226,6 @@ type wrappos: int # position of last wrapping opportunity, or -1 firstTextFragment: InlineFragment lastTextFragment: InlineFragment - errorY: LayoutUnit # rounding error distributed along lines InlineState = object computed: CSSComputedValues @@ -259,9 +263,6 @@ template atoms(state: LineBoxState): untyped = template size(state: LineBoxState): untyped = state.line.size -template offsety(state: var LineBoxState): untyped = - state.line.offsety - func size(ictx: var InlineContext): var Size = ictx.root.size @@ -309,7 +310,7 @@ proc newWord(ictx: var InlineContext, state: var InlineState) = ictx.hasshy = false proc horizontalAlignLine(ictx: var InlineContext, state: InlineState, - line: var LineBox, last = false) = + line: var LineBox) = let width = case ictx.space.w.t of MIN_CONTENT, MAX_CONTENT: ictx.size.w @@ -426,6 +427,7 @@ proc verticalAlignLine(ictx: var InlineContext) = for atom in ictx.currentLine.atoms: atom.offset.y += marginTop atom.offset.y += ictx.currentLine.paddingTop + atom.offset.y += ictx.currentLine.offsety # Set the line height to new top edge + old bottom edge, and set the # baseline. @@ -476,7 +478,7 @@ proc initLine(ictx: var InlineContext) = #TODO what if maxContent/minContent? if bctx.exclusions.len != 0: let bfcOffset = ictx.bfcOffset - let y = ictx.currentLine.line.offsety + bfcOffset.y + let y = ictx.currentLine.offsety + bfcOffset.y var left = bfcOffset.x var right = bfcOffset.x + ictx.currentLine.availableWidth for ex in bctx.exclusions: @@ -523,22 +525,21 @@ proc finishLine(ictx: var InlineContext, state: var InlineState, wrap: bool, else: state.fragment.size.w = max(lineWidth, state.fragment.size.w) ictx.size.w = max(ictx.size.w, lineWidth) - # count error - if ictx.lines.len > 0: - let dy = ictx.currentLine.line.offsety - ictx.lines[^1].offsety - ictx.errorY += dy - toInt(dy div ictx.cellheight) * ictx.cellheight ictx.lines.add(ictx.currentLine.line) + # round line height to real cell height, so that the next line will actually + # come after ours. + let ch = ictx.cellheight + ictx.currentLine.size.h = toInt(ictx.currentLine.size.h div ch) * ch ictx.currentLine = LineBoxState( - line: LineBox(offsety: y + ictx.currentLine.size.h) + offsety: y + ictx.currentLine.size.h, + line: LineBox() ) ictx.initLine() proc finish(ictx: var InlineContext, state: var InlineState) = ictx.finishLine(state, wrap = false) - if ictx.lines.len > 0: - for i in 0 ..< ictx.lines.len - 1: - ictx.horizontalAlignLine(state, ictx.lines[i], last = false) - ictx.horizontalAlignLine(state, ictx.lines[^1], last = true) + for line in ictx.lines.mitems: + ictx.horizontalAlignLine(state, line) func minwidth(atom: InlineAtom): LayoutUnit = if atom.t == INLINE_BLOCK: @@ -1368,7 +1369,7 @@ proc layoutInline(ictx: var InlineContext, box: InlineBoxBuilder): firstLine: true, startOffsetTop: Offset( x: ictx.currentLine.widthAfterWhitespace, - y: ictx.currentLine.line.offsety + y: ictx.currentLine.offsety ) ) if box.newline: @@ -1419,20 +1420,6 @@ proc layoutInline(ictx: var InlineContext, box: InlineBoxBuilder): state.startOffsetTop.y return fragment -proc positionAtoms(ictx: var InlineContext) = - if ictx.lines.len == 0: - return - let H = ictx.lines.len - 1 - let erry = if H != 0: - ictx.errorY / H - else: - 0 - for i in 1 ..< ictx.lines.len: - let erry0 = erry * i - let offsety = ictx.lines[i].offsety - for atom in ictx.lines[i].atoms: - atom.offset.y += offsety - erry0 - proc layoutRootInline(bctx: var BlockContext, inlines: seq[BoxBuilder], space: AvailableSpace, computed: CSSComputedValues, offset, bfcOffset: Offset): RootInlineFragment = @@ -1471,7 +1458,6 @@ proc layoutRootInline(bctx: var BlockContext, inlines: seq[BoxBuilder], var state = InlineState(computed: computed, fragment: lastFragment) ictx.finish(state) root.xminwidth = ictx.minwidth - ictx.positionAtoms() return root proc buildMarker(builder: MarkerBoxBuilder, space: AvailableSpace, |