Skip to content

random crash for missing glyph slot 19 #25

Description

@vickyleu

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()
        }

    }
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions