@@ -7,12 +7,9 @@ import android.graphics.Paint
7
7
import android.graphics.drawable.Drawable
8
8
import android.text.Editable
9
9
import android.text.Spannable
10
- import android.text.style.DynamicDrawableSpan
11
10
import android.text.style.ImageSpan
12
- import android.text.style.ReplacementSpan
13
11
import androidx.core.content.res.ResourcesCompat
14
12
import io.github.karino2.kotlitex.view.MathExpressionSpan
15
- import java.lang.ref.WeakReference
16
13
import org.json.JSONObject
17
14
import org.oppia.android.util.R
18
15
import org.oppia.android.util.logging.ConsoleLogger
@@ -154,44 +151,56 @@ class MathTagHandler(
154
151
155
152
/* * An [ImageSpan] that vertically centers a LaTeX drawable within the surrounding text. */
156
153
private class LatexImageSpan (
157
- private val drawable : Drawable ,
158
- private val isInline : Boolean
159
- ) : ReplacementSpan() {
154
+ imageDrawable : Drawable ? ,
155
+ private val isInlineMode : Boolean
156
+ ) : ImageSpan(imageDrawable ? : createEmptyDrawable()) {
157
+
160
158
companion object {
161
- private const val INLINE_SHIFT_FACTOR = 0.9f // Adjust this value (0.2-0.4) as needed
159
+ private const val INLINE_VERTICAL_SHIFT_RATIO = 0.9f
160
+
161
+ private fun createEmptyDrawable (): Drawable {
162
+ return object : Drawable () {
163
+ override fun draw (canvas : Canvas ) {}
164
+ override fun setAlpha (alpha : Int ) {}
165
+ override fun setColorFilter (colorFilter : android.graphics.ColorFilter ? ) {}
166
+ override fun getOpacity (): Int = android.graphics.PixelFormat .TRANSPARENT
167
+
168
+ init {
169
+ setBounds(0 , 0 , 1 , 1 )
170
+ }
171
+ }
172
+ }
162
173
}
163
174
164
175
override fun getSize (
165
176
paint : Paint ,
166
177
text : CharSequence ,
167
178
start : Int ,
168
179
end : Int ,
169
- fm : Paint .FontMetricsInt ?
180
+ fontMetrics : Paint .FontMetricsInt ?
170
181
): Int {
171
- val bounds = drawable.bounds
172
- val imageHeight = bounds.height()
173
- val paintMetrics = paint.fontMetricsInt
174
- val textHeight = paintMetrics.descent - paintMetrics.ascent
175
-
176
- fm?.let { metrics ->
177
- if (isInline) {
178
- // Reserve space for inline shift
182
+ val drawableBounds = drawable.bounds
183
+ val imageHeight = drawableBounds.height()
184
+ val textMetrics = paint.fontMetricsInt
185
+ val textHeight = textMetrics.descent - textMetrics.ascent
186
+
187
+ fontMetrics?.let { metrics ->
188
+ if (isInlineMode) {
179
189
val verticalShift = (imageHeight - textHeight) / 2 +
180
- (paintMetrics .descent * INLINE_SHIFT_FACTOR ).toInt()
181
- metrics.ascent = paintMetrics .ascent - verticalShift
190
+ (textMetrics .descent * INLINE_VERTICAL_SHIFT_RATIO ).toInt()
191
+ metrics.ascent = textMetrics .ascent - verticalShift
182
192
metrics.top = metrics.ascent
183
- metrics.descent = paintMetrics .descent + verticalShift
193
+ metrics.descent = textMetrics .descent + verticalShift
184
194
metrics.bottom = metrics.descent
185
195
} else {
186
- // Block mode calculations remain unchanged
187
196
val totalHeight = (imageHeight * 1.2 ).toInt()
188
197
metrics.ascent = - totalHeight / 2
189
198
metrics.top = metrics.ascent
190
199
metrics.descent = totalHeight / 2
191
200
metrics.bottom = metrics.descent
192
201
}
193
202
}
194
- return bounds .right
203
+ return drawableBounds .right
195
204
}
196
205
197
206
override fun draw (
@@ -208,20 +217,17 @@ private class LatexImageSpan(
208
217
canvas.save()
209
218
210
219
val imageHeight = drawable.bounds.height()
211
- val yPosition = when {
212
- isInline -> {
213
- // Apply downward shift for inline equations
214
- val textMidline = baseline - (paint.fontMetrics.descent - paint.fontMetrics.ascent) / 2
215
- val shiftOffset = (paint.fontMetricsInt.descent * INLINE_SHIFT_FACTOR ).toInt()
216
- textMidline - (imageHeight / 2 ) + shiftOffset
217
- }
218
- else -> {
219
- // Block mode remains centered
220
- lineTop + (lineBottom - lineTop - imageHeight) / 2
221
- }
220
+ val yOffset = if (isInlineMode) {
221
+ val metrics = paint.fontMetricsInt
222
+ val ascent = metrics.ascent.toFloat()
223
+ val descent = metrics.descent.toFloat()
224
+ val expectedCenterY = baseline.toFloat() + (ascent + descent) / 2f
225
+ expectedCenterY - (imageHeight / 2f )
226
+ } else {
227
+ lineTop.toFloat() + (lineBottom - lineTop - imageHeight) / 2f
222
228
}
223
229
224
- canvas.translate(x, yPosition.toFloat() )
230
+ canvas.translate(x, yOffset )
225
231
drawable.draw(canvas)
226
232
canvas.restore()
227
233
}
0 commit comments