mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 09:20:19 +01:00
Implement a cache for faster typeface resolution.
This commit is contained in:
committed by
Cody Henthorne
parent
46bb64ad24
commit
6fb6092a6b
@@ -8,7 +8,6 @@ import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.s3.S3
|
||||
import org.thoughtcrime.securesms.util.ListenableFutureTask
|
||||
import org.thoughtcrime.securesms.util.LocaleUtil
|
||||
import java.io.File
|
||||
import java.util.Collections
|
||||
import java.util.Locale
|
||||
@@ -52,12 +51,12 @@ object Fonts {
|
||||
*
|
||||
* @param context An application context
|
||||
* @param font The desired font
|
||||
* @param guessedScript The script likely being used based on text content
|
||||
* @param supportedScript The script likely being used based on text content
|
||||
*
|
||||
* @return a FontResult that represents either a Typeface or a task retrieving a Typeface.
|
||||
*/
|
||||
@WorkerThread
|
||||
fun resolveFont(context: Context, font: TextFont, guessedScript: SupportedScript = SupportedScript.UNKNOWN): FontResult {
|
||||
fun resolveFont(context: Context, font: TextFont, supportedScript: SupportedScript): FontResult {
|
||||
ThreadUtil.assertNotMainThread()
|
||||
synchronized(this) {
|
||||
val errorFallback = FontResult.Immediate(Typeface.create(font.fallbackFamily, font.fallbackStyle))
|
||||
@@ -70,8 +69,6 @@ object Fonts {
|
||||
|
||||
Log.d(TAG, "Loaded manifest.")
|
||||
|
||||
val localeDefaults: List<Locale> = LocaleUtil.getLocaleDefaults()
|
||||
val supportedScript: SupportedScript = getSupportedScript(localeDefaults, guessedScript)
|
||||
val fontScript = resolveFontScriptFromScriptName(supportedScript, manifest)
|
||||
if (fontScript == null) {
|
||||
Log.d(TAG, "Manifest does not have an entry for $supportedScript. Using default.")
|
||||
@@ -253,7 +250,7 @@ object Fonts {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSupportedScript(locales: List<Locale>, guessedScript: SupportedScript): SupportedScript {
|
||||
fun getSupportedScript(locales: List<Locale>, guessedScript: SupportedScript): SupportedScript {
|
||||
if (guessedScript != SupportedScript.UNKNOWN && guessedScript != SupportedScript.UNKNOWN_CJK) {
|
||||
return guessedScript
|
||||
} else if (guessedScript == SupportedScript.UNKNOWN_CJK) {
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.thoughtcrime.securesms.fonts
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import org.thoughtcrime.securesms.util.FutureTaskListener
|
||||
import org.thoughtcrime.securesms.util.LocaleUtil
|
||||
import java.util.Collections
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
||||
/**
|
||||
* In-Memory Typeface cache
|
||||
*/
|
||||
object TypefaceCache {
|
||||
|
||||
private val cache = Collections.synchronizedMap(mutableMapOf<CacheKey, Typeface>())
|
||||
|
||||
/**
|
||||
* Warms the typeface-cache with all fonts of a given script.
|
||||
*/
|
||||
fun warm(context: Context, script: SupportedScript) {
|
||||
val appContext = context.applicationContext
|
||||
TextFont.values().forEach {
|
||||
get(appContext, it, script).subscribe()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs the font and caches it on the fly.
|
||||
*/
|
||||
fun get(context: Context, font: TextFont, guessedScript: SupportedScript = SupportedScript.UNKNOWN): Single<Typeface> {
|
||||
val supportedScript = Fonts.getSupportedScript(LocaleUtil.getLocaleDefaults(), guessedScript)
|
||||
val cacheKey = CacheKey(supportedScript, font)
|
||||
val cachedValue = cache[cacheKey]
|
||||
val appContext = context.applicationContext
|
||||
|
||||
if (cachedValue != null) {
|
||||
return Single.just(cachedValue)
|
||||
} else {
|
||||
return Single.create<Typeface> { emitter ->
|
||||
when (val result = Fonts.resolveFont(appContext, font, supportedScript)) {
|
||||
is Fonts.FontResult.Immediate -> {
|
||||
cache[cacheKey] = result.typeface
|
||||
emitter.onSuccess(result.typeface)
|
||||
}
|
||||
is Fonts.FontResult.Async -> {
|
||||
val listener = object : FutureTaskListener<Typeface> {
|
||||
override fun onSuccess(typeface: Typeface) {
|
||||
cache[cacheKey] = typeface
|
||||
emitter.onSuccess(typeface)
|
||||
}
|
||||
|
||||
override fun onFailure(exception: ExecutionException) {
|
||||
emitter.onSuccess(result.placeholder)
|
||||
}
|
||||
}
|
||||
result.future.addListener(listener)
|
||||
emitter.setCancellable {
|
||||
result.future.removeListener(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.subscribeOn(Schedulers.io())
|
||||
}
|
||||
}
|
||||
|
||||
private data class CacheKey(
|
||||
val script: SupportedScript,
|
||||
val font: TextFont
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user