mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-10 00:16:59 +00:00
fix(math): align inline equations to the text baseline
This commit is contained in:
@@ -36,6 +36,7 @@ import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||
import androidx.compose.ui.graphics.nativeCanvas
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.rememberTextMeasurer
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.TextUnitType
|
||||
import androidx.compose.ui.unit.sp
|
||||
@@ -91,12 +92,33 @@ fun LatexEquation(
|
||||
return
|
||||
}
|
||||
|
||||
// Baseline alignment. The parent FlowRow centers each word vertically, so a
|
||||
// tight equation bitmap floats above the line — most of a formula's mass sits
|
||||
// above the baseline, so centering its box lifts the baseline above the text.
|
||||
// We pad the box so that, once centered, the equation's baseline coincides
|
||||
// with a surrounding text word's baseline. With text ascent/descent A/Dsc and
|
||||
// icon total height H and depth-below-baseline Dp, the padded box satisfies
|
||||
// `baseline-from-center = (A - Dsc) / 2` — the same value a Text box has — when
|
||||
// pad = (A - Dsc) - H + 2*Dp (on top if positive, on bottom if negative).
|
||||
val resolvedStyle = LocalTextStyle.current.let { if (fontSize.isUsable()) it else it.copy(fontSize = 16.sp) }
|
||||
val measurer = rememberTextMeasurer()
|
||||
val (drawTopPx, boxHeightPx) =
|
||||
remember(drawable, resolvedStyle) {
|
||||
val text = measurer.measure("Mg", resolvedStyle)
|
||||
val ascent = text.firstBaseline
|
||||
val descent = text.size.height - ascent
|
||||
val iconHeight = drawable.intrinsicHeight.toFloat()
|
||||
val iconDepth = drawable.icon().iconDepth.toFloat()
|
||||
val pad = (ascent - descent) - iconHeight + 2f * iconDepth
|
||||
maxOf(pad, 0f) to (iconHeight + maxOf(pad, 0f) + maxOf(-pad, 0f))
|
||||
}
|
||||
|
||||
val widthDp = with(density) { drawable.intrinsicWidth.toDp() }
|
||||
val heightDp = with(density) { drawable.intrinsicHeight.toDp() }
|
||||
val boxHeightDp = with(density) { boxHeightPx.toDp() }
|
||||
|
||||
// Wide display equations can overflow the column; allow them to scroll
|
||||
// horizontally instead of being clipped.
|
||||
val equationSize = Modifier.size(widthDp, heightDp)
|
||||
val equationSize = Modifier.size(widthDp, boxHeightDp)
|
||||
val equationModifier = if (displayMode) Modifier.horizontalScroll(rememberScrollState()).then(equationSize) else equationSize
|
||||
|
||||
// Row keeps leading/trailing punctuation (the `(` and `)` in `($x$)`) hugging
|
||||
@@ -107,8 +129,13 @@ fun LatexEquation(
|
||||
}
|
||||
Canvas(modifier = equationModifier) {
|
||||
drawIntoCanvas { canvas ->
|
||||
val native = canvas.nativeCanvas
|
||||
val checkpoint = native.save()
|
||||
// Position the icon's baseline on the text baseline within the padded box.
|
||||
native.translate(0f, drawTopPx)
|
||||
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
|
||||
drawable.draw(canvas.nativeCanvas)
|
||||
drawable.draw(native)
|
||||
native.restoreToCount(checkpoint)
|
||||
}
|
||||
}
|
||||
if (trailing.isNotEmpty()) {
|
||||
|
||||
Reference in New Issue
Block a user