
androidAndroidTest.androidx.compose.ui.text.TextTestExtensions.kt Maven / Gradle / Ivy
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.ui.text
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.text.font.AndroidFontLoader
import androidx.compose.ui.text.font.AndroidFontResolveInterceptor
import androidx.compose.ui.text.font.AsyncTypefaceCache
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontFamilyResolverImpl
import androidx.compose.ui.text.font.FontListFontFamilyTypefaceAdapter
import androidx.compose.ui.text.font.PlatformFontFamilyTypefaceAdapter
import androidx.compose.ui.text.font.PlatformFontLoader
import androidx.compose.ui.text.font.PlatformResolveInterceptor
import androidx.compose.ui.text.font.TypefaceRequestCache
import androidx.compose.ui.graphics.drawscope.DrawStyle
import androidx.compose.ui.text.style.TextDecoration
import kotlin.math.ceil
import kotlin.math.roundToInt
@OptIn(ExperimentalTextApi::class)
fun Paragraph.bitmap(
color: Color = Color.Unspecified,
shadow: Shadow? = null,
textDecoration: TextDecoration? = null,
drawStyle: DrawStyle? = null
): Bitmap {
val bitmap = Bitmap.createBitmap(
width.toIntPx(),
height.toIntPx(),
Bitmap.Config.ARGB_8888
)
this.paint(
canvas = androidx.compose.ui.graphics.Canvas(Canvas(bitmap)),
color = color,
shadow = shadow,
textDecoration = textDecoration,
drawStyle = drawStyle
)
return bitmap
}
@OptIn(ExperimentalTextApi::class)
fun Paragraph.bitmap(
brush: Brush,
alpha: Float,
shadow: Shadow? = null,
textDecoration: TextDecoration? = null,
drawStyle: DrawStyle? = null
): Bitmap {
val bitmap = Bitmap.createBitmap(
width.toIntPx(),
height.toIntPx(),
Bitmap.Config.ARGB_8888
)
this.paint(
canvas = androidx.compose.ui.graphics.Canvas(Canvas(bitmap)),
brush = brush,
alpha = alpha,
shadow = shadow,
textDecoration = textDecoration,
drawStyle = drawStyle
)
return bitmap
}
/**
* MultiParagraph creates Paragraphs to vertically layout. However, a Paragraph is an immutable
* object that cannot be changed after its creation. Thus, Brush evaluation according to the total
* size of MultiParagraph cannot be delegated to Paragraph instances during initialization.
*
* We have to re-specify the brush during paint(draw) to apply it according to the total size of
* MultiParagraph.
*/
@OptIn(ExperimentalTextApi::class)
fun MultiParagraph.bitmap(
brush: Brush? = null,
alpha: Float = Float.NaN
): Bitmap {
val width = paragraphInfoList.maxByOrNull { it.paragraph.width }?.paragraph?.width ?: 0f
val bitmap = Bitmap.createBitmap(
width.toIntPx(),
height.toIntPx(),
Bitmap.Config.ARGB_8888
)
if (brush != null) {
this.paint(
canvas = androidx.compose.ui.graphics.Canvas(Canvas(bitmap)),
brush = brush,
alpha = alpha
)
} else {
this.paint(
canvas = androidx.compose.ui.graphics.Canvas(Canvas(bitmap))
)
}
return bitmap
}
@OptIn(ExperimentalTextApi::class)
internal fun UncachedFontFamilyResolver(
context: Context
): FontFamily.Resolver = UncachedFontFamilyResolver(
AndroidFontLoader(context),
AndroidFontResolveInterceptor(context)
)
@OptIn(ExperimentalTextApi::class)
internal fun UncachedFontFamilyResolver(
platformFontLoader: PlatformFontLoader,
platformResolveInterceptor: PlatformResolveInterceptor
): FontFamily.Resolver = FontFamilyResolverImpl(
platformFontLoader,
platformResolveInterceptor,
TypefaceRequestCache(),
FontListFontFamilyTypefaceAdapter(AsyncTypefaceCache()),
PlatformFontFamilyTypefaceAdapter()
)
fun Float.toIntPx(): Int = ceil(this).roundToInt()
internal fun FloatArray.asRectArray(): Array {
return Array((size) / 4) { index ->
Rect(
this[4 * index],
this[4 * index + 1],
this[4 * index + 2],
this[4 * index + 3]
)
}
}
internal fun getLtrCharacterBoundariesForTestFont(
text: String,
fontSize: Float,
// assumes that the test font is used and fontSize is equal to default line height
lineHeight: Float = fontSize,
initialTop: Float = 0f
): Array {
var top = initialTop
var left = 0f
return text.indices.map { index ->
// if \n, no position update, same as before
val right = if (text[index] == '\n') left else left + fontSize
val bottom = top + lineHeight
Rect(
left = left,
top = top,
right = right,
bottom = bottom
).also {
if (text[index] == '\n') {
// left resets to line start
left = 0f
// top will go to next line
top = bottom
} else {
// else move to right with one char
left = right
}
}
}.toTypedArray()
}
internal fun getRtlCharacterBoundariesForTestFont(
text: String,
width: Float,
fontSize: Float,
lineHeight: Float = fontSize
): Array {
var top = 0f
var right = width
return text.indices.map { index ->
// if \n, position doesn't update, same as before (right)
// else left is 1 char left
val left = if (text[index] == '\n') right else right - fontSize
val bottom = top + lineHeight
Rect(
left = left,
top = top,
right = right,
bottom = bottom
).also {
if (text[index] == '\n') {
// right resets to line start
right = width
// top will go to next line
top = bottom
} else {
// else move to left with one char
right = left
}
}
}.toTypedArray()
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy