AndroidMath
AndroidMath copied to clipboard
random crash for missing glyph slot 19
latex
{1}_{2}
crash detail
com.zzhoujay.richtext.mathdisplay.parse.MathDisplayException
missing glyph slot 19.
1
java.lang.RuntimeException:java.lang.reflect.InvocationTargetException
2
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:594)
3
......
4
Caused by:
5
com.zzhoujay.richtext.mathdisplay.parse.MathDisplayException:missing glyph slot 19.
6
com.zzhoujay.richtext.mathdisplay.render.MTDrawFreeType.drawGlyph(MTDrawFreeType.kt:22)
7
com.zzhoujay.richtext.mathdisplay.render.MTCTLineDisplay.draw(MTMathListDisplay.kt:149)
8
com.zzhoujay.richtext.mathdisplay.render.MTMathListDisplay.draw(MTMathListDisplay.kt:227)
9
com.zzhoujay.richtext.mathdisplay.render.MTMathListDisplay.draw(MTMathListDisplay.kt:227)
10
com.zzhoujay.richtext.spans.MTMathSpan.draw(MTMathSpan.kt:313)
11
android.text.TextLine.handleReplacement(TextLine.java:1120)
12
android.text.TextLine.handleRun(TextLine.java:1269)
13
android.text.TextLine.drawRun(TextLine.java:536)
14
android.text.TextLine.draw(TextLine.java:303)
15
android.text.Layout.drawText(Layout.java:599)
16
android.text.Layout.draw(Layout.java:346)
17
android.widget.TextView.onDraw(TextView.java:8436)
18
android.view.View.draw(View.java:23424)
19
android.view.View.updateDisplayListIfDirty(View.java:22262)
20
android.view.View.draw(View.java:23139)
21
android.view.ViewGroup.drawChild(ViewGroup.java:4614)
22
android.view.ViewGroup.dispatchDraw(ViewGroup.java:4367)
23
android.view.View.draw(View.java:23427)
24
androidx.compose.ui.platform.AndroidViewsHandler.drawView(AndroidViewsHandler.android.kt:79)
25
androidx.compose.ui.platform.AndroidComposeView.drawAndroidView(AndroidComposeView.android.kt:1218)
26
androidx.compose.ui.viewinterop.AndroidViewHolder$layoutNode$1$coreModifier$2.invoke(AndroidViewHolder.android.kt:358)
27
androidx.compose.ui.viewinterop.AndroidViewHolder$layoutNode$1$coreModifier$2.invoke(AndroidViewHolder.android.kt:353)
28
androidx.compose.ui.draw.DrawBackgroundModifier.draw(DrawModifier.kt:127)
29
androidx.compose.ui.node.LayoutNodeDrawScope.drawDirect-eZhPAX0$ui_release(LayoutNodeDrawScope.kt:110)
30
androidx.compose.ui.node.LayoutNodeDrawScope.draw-eZhPAX0$ui_release(LayoutNodeDrawScope.kt:89)
31
androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:450)
32
androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:439)
33
androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:280)
34
androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:447)
35
androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:439)
36
androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:280)
37
androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:447)
38
androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:439)
39
androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:280)
40
androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:447)
41
androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:439)
42
androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:280)
43
androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:447)
44
androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:439)
45
androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:1000)
46
androidx.compose.ui.node.InnerNodeCoordinator.performDraw(InnerNodeCoordinator.kt:196)
47
androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:447)
48
androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:439)
49
androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:280)
50
androidx.compose.ui.node.LayoutNodeDrawScope.drawContent(LayoutNodeDrawScope.kt:68)
51
androidx.compose.foundation.BackgroundNode.draw(Background.kt:163)
52
androidx.compose.ui.node.LayoutNodeDrawScope.drawDirect-eZhPAX0$ui_release(LayoutNodeDrawScope.kt:110)
53
androidx.compose.ui.node.LayoutNodeDrawScope.draw-eZhPAX0$ui_release(LayoutNodeDrawScope.kt:89)
54
androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:450)
55
androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:439)
56
androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:280)
57
androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:447)
58
androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:439)
59
androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:280)
60
androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:447)
61
androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:439)
62
androidx.compose.ui.node.LayoutModifierNodeCoordinator.performDraw(LayoutModifierNodeCoordinator.kt:280)
63
androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:447)
64
androidx.compose.ui.node.NodeCoordinator.draw(NodeCoordinator.kt:439)
65
androidx.compose.ui.node.LayoutNode.draw$ui_release(LayoutNode.kt:1000)
66
androidx.compose.ui.node.InnerNodeCoordinator.performDraw(InnerNodeCoordinator.kt:196)
67
androidx.compose.ui.node.LayoutNodeDrawScope.drawContent(LayoutNodeDrawScope.kt:68)
68
androidx.compose.foundation.BackgroundNode.draw(Background.kt:163)
69
androidx.compose.ui.node.LayoutNodeDrawScope.drawDirect-eZhPAX0$ui_release(LayoutNodeDrawScope.kt:110)
70
androidx.compose.ui.node.LayoutNodeDrawScope.draw-eZhPAX0$ui_release(LayoutNodeDrawScope.kt:89)
71
androidx.compose.ui.node.NodeCoordinator.drawContainedDrawModifiers(NodeCoordinator.kt:450)
72
androidx.compose.ui.node.NodeCoordinator.access$drawContainedDrawModifiers(NodeCoordinator.kt:58)
73
androidx.compose.ui.node.NodeCoordinator$drawBlock$1$1.invoke(NodeCoordinator.kt:469)
74
androidx.compose.ui.node.NodeCoordinator$drawBlock$1$1.invoke(NodeCoordinator.kt:468)
75
androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2441)
76
androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:502)
77
androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:258)
78
androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
79
androidx.compose.ui.node.NodeCoordinator$drawBlock$1.invoke(NodeCoordinator.kt:468)
80
androidx.compose.ui.node.NodeCoordinator$drawBlock$1.invoke(NodeCoordinator.kt:466)
81
androidx.compose.ui.platform.GraphicsLayerOwnerLayer$recordLambda$1.invoke(GraphicsLayerOwnerLayer.android.kt:291)
82
androidx.compose.ui.platform.GraphicsLayerOwnerLayer$recordLambda$1.invoke(GraphicsLayerOwnerLayer.android.kt:289)
83
androidx.compose.ui.graphics.layer.GraphicsLayer$clipDrawBlock$1.invoke(AndroidGraphicsLayer.android.kt:71)
84
androidx.compose.ui.graphics.layer.GraphicsLayer$clipDrawBlock$1.invoke(AndroidGraphicsLayer.android.kt:66)
85
androidx.compose.ui.graphics.layer.GraphicsLayerV29.record(GraphicsLayerV29.android.kt:251)
86
androidx.compose.ui.graphics.layer.GraphicsLayer.recordInternal(AndroidGraphicsLayer.android.kt:436)
87
androidx.compose.ui.graphics.layer.GraphicsLayer.record-mL-hObY(AndroidGraphicsLayer.android.kt:429)
88
androidx.compose.ui.platform.GraphicsLayerOwnerLayer.updateDisplayList(GraphicsLayerOwnerLayer.android.kt:284)
89
androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:1573)
90
android.view.View.draw(View.java:23427)
91
android.view.View.updateDisplayListIfDirty(View.java:22262)
92
android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4594)
93
android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4567)
94
android.view.View.updateDisplayListIfDirty(View.java:22213)
95
android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4594)
96
android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4567)
97
android.view.View.updateDisplayListIfDirty(View.java:22213)
98
android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4594)
99
android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4567)
100
android.view.View.updateDisplayListIfDirty(View.java:22213)
101
android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4594)
102
android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4567)
103
android.view.View.updateDisplayListIfDirty(View.java:22213)
104
android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:682)
105
android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:688)
106
android.view.ThreadedRenderer.draw(ThreadedRenderer.java:790)
107
android.view.ViewRootImpl.draw(ViewRootImpl.java:4869)
108
android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4564)
109
android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3750)
110
android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2458)
111
android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9415)
112
android.view.Choreographer$CallbackRecord.run(Choreographer.java:1388)
113
android.view.Choreographer$CallbackRecord.run(Choreographer.java:1396)
114
android.view.Choreographer.doCallbacks(Choreographer.java:1033)
115
android.view.ChoreographerExtImpl.checkScrollOptSceneEnable(ChoreographerExtImpl.java:420)
116
android.view.Choreographer.doFrame(Choreographer.java:900)
117
android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1371)
118
android.os.Handler.handleCallback(Handler.java:942)
119
android.os.Handler.dispatchMessage(Handler.java:99)
120
android.os.Looper.loopOnce(Looper.java:240)
121
android.os.Looper.loop(Looper.java:351)
122
android.app.ActivityThread.main(ActivityThread.java:8377)
123
java.lang.reflect.Method.invoke(Native Method)
124
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
125
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1013)
code
val span = MTMathSpan().apply {
this.latex = "{1}_{2}"
this.textColor = Color.BLACK
val fSize =
context.resources.displayMetrics.scaledDensity * textSizeSp
this.fontSize = fSize
this.font = MTFontManager.latinModernFontWithSize(fSize)
this.labelMode = MTMathSpan.MTMathViewMode.KMTMathViewModeText
this.textAlignment =
MTMathSpan.MTTextAlignment.KMTTextAlignmentLeft
this.displayErrorInline = true
}
class MTMathSpan : ReplacementSpan() {
private var displayList: MTMathListDisplay? = null
private var _mathList: MTMathList? = null
/**
* Holds the error status from the last parse of the LaTeX string.
* The errorcode of this can be checked to determine if the string was well formatted.
*/
val lastError = MTParseError()
/**
* Not normally used. Only if you are building a mathlist in code.
* Standard usage is setting a String in latex property.
*/
var mathList: MTMathList? = null
set(value) {
field = value
if (value != null) {
latex = MTMathListBuilder.toLatexString(value)
}
}
/**
* The LaTeX Math string to display in the view.
*
* Sample mathview.latex = "x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}"
*/
var latex: String = ""
set(value) {
field = value
MTMathListBuilder.Factory
MTMathListBuilder.buildFromString(value, lastError).let {
if(lastError.errorcode != MTParseErrors.ErrorNone) {
this._mathList = null
}else{
this._mathList = it
}
}
displayList = null
// requestLayout()
// invalidate()
}
/**
* Different display styles supported by the `MTMathView`.
*
* The only significant difference between the two modes is how fractions
* and limits on large operators are displayed.
*/
enum class MTMathViewMode {
/// Display mode. Equivalent to $$ in TeX
KMTMathViewModeDisplay,
/// Text mode. Equivalent to $ in TeX.
KMTMathViewModeText
}
/**
* If view width is not measured to fit equation size this will specify placement within the view.
* See **textAlignment**
*/
enum class MTTextAlignment {
/// Align left.
KMTTextAlignmentLeft,
/// Align center.
KMTTextAlignmentCenter,
/// Align right.
KMTTextAlignmentRight
}
/**
* If true the default parse errors will be drawn as text instead of math equation.
* Default value is true
*/
var displayErrorInline = true
/**
* Font used to draw the equation. See MTFontManager
*/
var font: MTFont? = MTFontManager.defaultFont()
set(value) {
field = value
displayList = null
// requestLayout()
// invalidate()
}
/**
* This is in device pixels. Default value is see KDefaultFontSize
*/
var fontSize = KDefaultFontSize // This is in device pixels.
set(value) {
field = value
val of = this.font
if (of != null) {
val f = of.copyFontWithSize(value)
this.font = f
}
}
/**
* Should display or text mode be used.
*/
var labelMode = MTMathViewMode.KMTMathViewModeDisplay
set(value) {
field = value
displayList = null
// requestLayout()
// invalidate()
}
/**
* Color of the equation if not overridden with local color changes by TeX commands
*/
var textColor = Color.BLACK
set(value) {
field = value
val dl = displayList
if (dl != null) {
dl.textColor = value
}
// invalidate()
}
/**
* Alignment within the view
*/
var textAlignment = MTTextAlignment.KMTTextAlignmentLeft
set(value) {
field = value
// requestLayout()
// invalidate()
}
private var currentStyle = MTLineStyle.KMTLineStyleDisplay
get() {
return when (labelMode) {
MTMathViewMode.KMTMathViewModeDisplay -> MTLineStyle.KMTLineStyleDisplay
MTMathViewMode.KMTMathViewModeText -> MTLineStyle.KMTLineStyleText
}
}
private fun displayError(): Boolean {
return (lastError.errorcode != MTParseErrors.ErrorNone &&
this.displayErrorInline)
}
/**
* When parsing errors are drawn this will control the size of the resulting error text and therefore view measured size.
* In device pixels
*/
val errorFontSize = 20.0f
companion object {
/**
* Utility function to convert device independent pixel values to device pixels
*/
private fun convertDpToPixel(dp: Float): Float {
val metrics = Resources.getSystem().displayMetrics
val px = dp * (metrics.densityDpi / 160f)
return Math.round(px).toFloat()
}
}
private fun drawError(canvas: Canvas, x: Float, y: Float): Boolean {
if (!displayError()) {
return false
}
val paint = Paint()
paint.typeface = Typeface.DEFAULT
val r = errorBounds()
val path = android.graphics.Path()
val left =x
val top = y-r.height()
val right = left+r.width()
val bottom =top+convertDpToPixel(errorFontSize)*1.2f
path.moveTo(left,top)
path.lineTo(right,top)
path.lineTo(right,bottom)
path.lineTo(left,bottom)
path.close()
canvas.drawPath(path,paint)
// canvas.drawPaint(paint)
paint.color = Color.RED
paint.textSize = convertDpToPixel(errorFontSize)
println("lastError.errordesc::${lastError.errordesc}")
canvas.drawText("公式错误,请仔细检查", x, y, paint)
return true
}
private fun errorBounds(): Rect {
if (displayError()) {
val paint = Paint()
paint.typeface = Typeface.DEFAULT// your preference here
paint.textSize = convertDpToPixel(errorFontSize)
val bounds = Rect()
paint.getTextBounds(lastError.errordesc, 0, lastError.errordesc!!.length, bounds)
return bounds
} else {
return Rect(0, 0, 0, 0)
}
}
override fun getSize(
paint: Paint,
text: CharSequence?,
start: Int,
end: Int,
fm: Paint.FontMetricsInt?
): Int {
val size =getMeasuredSize()
fm?.let {
var dl = displayList
val ml = this._mathList
if (ml != null && dl == null) {
displayList = MTTypesetter.createLineForMathList(ml, font!!, currentStyle)
dl = displayList
}
val ascent = dl?.ascent?:0f
val descent = dl?.descent?:0f
// 设置 FontMetricsInt 参数
it.ascent = -(ascent.toInt().absoluteValue+10)
it.descent = descent.toInt().absoluteValue+10
it.top = it.ascent// 根据需要调整顶部距离
it.bottom = it.descent // 根据需要调整底部距离
it.leading = 0
}
//下面是view种计算宽高的方法.如何将这个应用到ReplacementSpan 的 getSize中
return size.width
}
fun getMeasuredSize(): Size {
var dl = displayList
val ml = this._mathList
if (ml != null && dl == null) {
displayList = MTTypesetter.createLineForMathList(ml, font!!, currentStyle)
dl = displayList
}
var height = 0.0f
var width = 0.0f
if (dl != null) {
height = dl.ascent + dl.descent
width = dl.width
}
val r = errorBounds()
height = maxOf(height, r.height().toFloat())
width = maxOf(width, r.width().toFloat())
return Size((width + 1.0f).toInt(), (height + 1.0f).toInt())
}
override fun draw(
canvas: Canvas,
text: CharSequence?,
start: Int,
end: Int,
x: Float,
top: Int,
y: Int,
bottom: Int,
paint: Paint
) {
// call the super method to keep any drawing from the parent side.
if (drawError(canvas,x, y+top.toFloat())) {
return
}
val size = getMeasuredSize()
val width = size.width
val height = size.height
var dl = displayList
val ml = this._mathList
if (ml != null && dl == null) {
displayList = MTTypesetter.createLineForMathList(ml, font!!, currentStyle)
dl = displayList
}
if (dl != null) {
dl.textColor = this.textColor
// Determine x position based on alignment
dl.position.x =0f//textX.toFloat()
dl.position.y =0f// textY
canvas.save()
canvas.translate(x, y.toFloat())
canvas.scale(1.0f, -1.0f)
dl.draw(canvas)
canvas.restore()
}
}
}