neiam
/diogramos
diogramos
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
Fix canvas text rendering at density times its intended size
b453bb1 · Gabriel Morell · 2026-09-16 03:25
Message
{commit_body(@commit)}
Files changed
modified
android/app/src/main/java/org/neiam/diogramos/app/canvas/Renderer.kt
+16
−4
@@ -17,7 +17,7 @@ import androidx.compose.ui.text.font.FontStyle
| 17 | 17 | import androidx.compose.ui.text.font.FontWeight |
| 18 | 18 | import androidx.compose.ui.text.style.TextAlign |
| 19 | 19 | import androidx.compose.ui.unit.Constraints |
| 20 | −import androidx.compose.ui.unit.sp | |
| 20 | + | |
| 21 | 21 | import org.neiam.diogramos.app.ui.theme.AppTheme |
| 22 | 22 | import org.neiam.diogramos.app.ui.theme.B612 |
| 23 | 23 | import kotlin.math.atan2 |
@@ -180,11 +180,23 @@ class Renderer(
| 180 | 180 | val isText = element.type == ElementType.TEXT |
| 181 | 181 | val style = element.style |
| 182 | 182 | |
| 183 | − val fontSize = when { | |
| 183 | + // Document units scaled by the zoom, so this is device pixels. | |
| 184 | + val fontSizePx = when { | |
| 184 | 185 | isText -> (style.fontSize ?: 16.0) * viewport.scale |
| 185 | 186 | else -> labelSizePx(style.labelSize) * viewport.scale |
| 186 | 187 | } |
| 187 | − if (fontSize < 4f) return // Below this it is noise, not text. | |
| 188 | + if (fontSizePx < 4f) return // Below this it is noise, not text. | |
| 189 | + | |
| 190 | + // px -> sp, deliberately. `sp` is scaled by both display density | |
| 191 | + // and the reader's font-size setting, so handing it a pixel count | |
| 192 | + // renders the text density-times too large -- and since the wrap | |
| 193 | + // width below is in real pixels, every word then overflows its box | |
| 194 | + // and the label wraps after each character. | |
| 195 | + // | |
| 196 | + // This is also why canvas text must not follow the system font | |
| 197 | + // scale: a diagram's text has to fit the box it was drawn in, the | |
| 198 | + // same way `font_size` is in user units on the web. | |
| 199 | + val fontSize = with(scope) { fontSizePx.toFloat().toSp() } | |
| 188 | 200 | |
| 189 | 201 | val color = when { |
| 190 | 202 | isText -> style.fill?.let { theme.token(it) } ?: theme.baseContent |
@@ -195,7 +207,7 @@ class Renderer(
| 195 | 207 | text = element.label, |
| 196 | 208 | style = TextStyle( |
| 197 | 209 | color = color, |
| 198 | − fontSize = fontSize.sp, | |
| 210 | + fontSize = fontSize, | |
| 199 | 211 | fontFamily = fontFamily(if (isText) style.fontFamily else style.labelFontFamily), |
| 200 | 212 | fontWeight = if (if (isText) style.fontBold else style.labelBold) { |
| 201 | 213 | FontWeight.Bold |
Parents: b018a0f