From e346f06c67e2b7af8675164375fd7769335e87db Mon Sep 17 00:00:00 2001 From: Bixilon Date: Tue, 13 Jun 2023 22:10:51 +0200 Subject: [PATCH] text wrapping fixes --- .../component/ChatComponentRendererTest.kt | 67 +++++++++++++++++++ .../component/TextComponentRenderer.kt | 11 +-- .../font/renderer/element/TextOffset.kt | 24 ++++--- 3 files changed, 90 insertions(+), 12 deletions(-) diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRendererTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRendererTest.kt index 627c0186a..ff0f9fa89 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRendererTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/font/renderer/component/ChatComponentRendererTest.kt @@ -185,5 +185,72 @@ class ChatComponentRendererTest { ) } + fun `no space x`() { + val info = render(TextComponent("bcd\n\nefgh"), maxSize = Vec2(0.0f, Float.MAX_VALUE)) + info.assert( + lineIndex = 0, + lines = listOf(), + size = Vec2(0.0f, 0.0f), + cutOff = true, + ) + } + + fun `no space y`() { + val info = render(TextComponent("bcd\n\nefgh"), maxSize = Vec2(Float.MAX_VALUE, 0.0f)) + info.assert( + lineIndex = 0, + lines = listOf(), + size = Vec2(0.0f, 0.0f), + cutOff = true, + ) + } + + fun `no space`() { + val info = render(TextComponent("bcd\n\nefgh"), maxSize = Vec2(0.0f, 0.0f)) + info.assert( + lineIndex = 0, + lines = listOf(), + size = Vec2(0.0f, 0.0f), + cutOff = true, + ) + } + + fun `size limit one line`() { + val info = render(TextComponent("bcd\nefgh"), maxSize = Vec2(Float.MAX_VALUE, 11.0f)) + info.assert( + lineIndex = 0, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f), + ), + size = Vec2(5.0f, 11.0f), + cutOff = true, + ) + } + + fun `size limit one line with overflow`() { + val info = render(TextComponent("bcd\nefgh"), maxSize = Vec2(5.0f, 11.0f)) + info.assert( + lineIndex = 0, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f), + ), + size = Vec2(5.0f, 11.0f), + cutOff = true, + ) + } + + fun `size limit two line`() { + val info = render(TextComponent("bcd\nefgh\nabc"), maxSize = Vec2(Float.MAX_VALUE, 22.0f)) + info.assert( + lineIndex = 1, + lines = listOf( + TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f), + TextLineInfo(BaseComponent(TextComponent("efgh")), 14.0f), + ), + size = Vec2(14.0f, 22.0f), + cutOff = true, + ) + } + // TODO: shadow, cutoff, underline, strikethrough, using with consumer, formatting (just basic, that is code point renderer's job) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/TextComponentRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/TextComponentRenderer.kt index 8d7e86532..b776622b3 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/TextComponentRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/component/TextComponentRenderer.kt @@ -43,7 +43,7 @@ object TextComponentRenderer : ChatComponentRenderer { private fun renderNewline(properties: TextRenderProperties, offset: TextOffset, info: TextRenderInfo, updateSize: Boolean): Boolean { val height = offset.getNextLineHeight(properties) - if (!offset.addLine(info, height)) { + if (!offset.addLine(info, properties.lineHeight, height)) { info.cutOff = true return true } @@ -75,10 +75,13 @@ object TextComponentRenderer : ChatComponentRenderer { val line = StringBuilder() var filled = false - for (codePoint in text.message.codePoints()) { + val stream = text.message.codePoints().iterator() + while (stream.hasNext()) { + val codePoint = stream.nextInt() if (codePoint == '\n'.code) { + val lineIndex = info.lineIndex filled = renderNewline(properties, offset, info, consumer == null) - info.lines[info.lineIndex - 1].push(text, line) + info.lines[lineIndex].push(text, line) skipWhitespaces = true if (filled) break else continue } @@ -98,11 +101,11 @@ object TextComponentRenderer : ChatComponentRenderer { val lineIndex = info.lineIndex val lineInfo = renderer.render(offset, color, properties, info, formatting, codePoint, consumer, options) - if (consumer != null) continue // already know that information if (lineInfo == CodePointAddResult.BREAK) { filled = true break } + if (consumer != null) continue // already know that information if (lineIndex != info.lineIndex) { // new line started diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextOffset.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextOffset.kt index b713a0e60..76511f277 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextOffset.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/font/renderer/element/TextOffset.kt @@ -34,12 +34,16 @@ class TextOffset( return fits(offset.x, initial.x, info.maxSize.x, width) } - fun fitsY(info: TextRenderInfo, height: Float): Boolean { - return fits(offset.y, initial.y, info.maxSize.y, height) + fun fitsY(info: TextRenderInfo, offset: Float, height: Float): Boolean { + return fits(this.offset.y + offset, initial.y, info.maxSize.y, height) + } + + fun canEverFit(info: TextRenderInfo, width: Float): Boolean { + return info.maxSize.x >= width } fun fitsInLine(properties: TextRenderProperties, info: TextRenderInfo, width: Float): Boolean { - return fitsX(info, width) && fitsY(info, properties.lineHeight) + return fitsX(info, width) && fitsY(info, 0.0f, properties.lineHeight) } fun getNextLineHeight(properties: TextRenderProperties): Float { @@ -49,11 +53,11 @@ class TextOffset( return height } - fun addLine(info: TextRenderInfo, height: Float): Boolean { - if (!fitsY(info, height)) return false + fun addLine(info: TextRenderInfo, offset: Float, height: Float): Boolean { + if (!fitsY(info, offset, height)) return false - offset.y += height - offset.x = initial.x + this.offset.y += height + this.offset.x = initial.x info.lines += TextLineInfo() info.lineIndex++ @@ -62,8 +66,12 @@ class TextOffset( fun canAdd(properties: TextRenderProperties, info: TextRenderInfo, width: Float, height: Float): CodePointAddResult { + if (!canEverFit(info, width)) { + info.cutOff = true + return CodePointAddResult.BREAK + } if (fitsInLine(properties, info, width)) return CodePointAddResult.FINE - if (addLine(info, height) && fitsInLine(properties, info, width)) return CodePointAddResult.NEW_LINE + if (addLine(info, 0.0f, height) && fitsInLine(properties, info, width)) return CodePointAddResult.NEW_LINE info.cutOff = true return CodePointAddResult.BREAK