From cc1d63cb81c6dbaf084da4964b7a10d9472c82bf Mon Sep 17 00:00:00 2001 From: jackyzy823 Date: Wed, 31 Jan 2024 13:28:06 +0800 Subject: [PATCH] Bug 1879116 - Repalce coil-kt with AndroidSVG --- .../components/browser/icons/build.gradle | 2 +- .../browser/icons/decoder/SvgIconDecoder.kt | 135 ++++++++++++--------- .../src/main/java/DependenciesPlugin.kt | 11 +- 3 files changed, 78 insertions(+), 70 deletions(-) rewrite mobile/android/android-components/components/browser/icons/src/main/java/mozilla/components/browser/icons/decoder/SvgIconDecoder.kt (60%) diff --git a/mobile/android/android-components/components/browser/icons/build.gradle b/mobile/android/android-components/components/browser/icons/build.gradle index bcfeacaab8c0..a0117897fb82 100644 --- a/mobile/android/android-components/components/browser/icons/build.gradle +++ b/mobile/android/android-components/components/browser/icons/build.gradle @@ -66,7 +66,7 @@ dependencies { implementation ComponentsDependencies.thirdparty_disklrucache - implementation ComponentsDependencies.thirdparty_coil_svg + implementation ComponentsDependencies.thirdparty_androidsvg testImplementation project(':support-test') testImplementation project(':lib-fetch-httpurlconnection') diff --git a/mobile/android/android-components/components/browser/icons/src/main/java/mozilla/components/browser/icons/decoder/SvgIconDecoder.kt b/mobile/android/android-components/components/browser/icons/src/main/java/mozilla/components/browser/icons/decoder/SvgIconDecoder.kt dissimilarity index 60% index 1b9a9e66fd39..455690638f76 100644 --- a/mobile/android/android-components/components/browser/icons/src/main/java/mozilla/components/browser/icons/decoder/SvgIconDecoder.kt +++ b/mobile/android/android-components/components/browser/icons/src/main/java/mozilla/components/browser/icons/decoder/SvgIconDecoder.kt @@ -1,60 +1,75 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package mozilla.components.browser.icons.decoder - -import android.content.Context -import android.graphics.Bitmap -import androidx.core.graphics.drawable.toBitmap -import coil.ImageLoader -import coil.decode.SvgDecoder -import coil.executeBlocking -import coil.request.CachePolicy -import coil.request.ImageRequest -import mozilla.components.support.base.log.logger.Logger -import mozilla.components.support.images.DesiredSize -import mozilla.components.support.images.decoder.ImageDecoder - -/** - * [ImageDecoder] that will use the Coil library [SvgDecoder.Factory] in order to decode the byte data. - * - * ⚠️ For guidance on use of the Coil library see comment for [ComponentsDependencies.thirdparty_coil_svg]. - */ -class SvgIconDecoder(val context: Context) : ImageDecoder { - private val logger = Logger("SvgIconDecoder") - - override fun decode(data: ByteArray, desiredSize: DesiredSize): Bitmap? = - try { - val request = ImageRequest.Builder(context) - .size(desiredSize.targetSize) - .data(data) - .build() - - SvgImageLoader.getInstance(context).executeBlocking(request).drawable?.toBitmap() - } catch (e: OutOfMemoryError) { - logger.error("Failed to decode the byte data due to OutOfMemoryError") - null - } - - private object SvgImageLoader { - @Volatile - private var instance: ImageLoader? = null - - /** - * Gets the [instance]. If [instance] is null also initialise the [ImageLoader]. - * @return the instance of the [ImageLoader]. - */ - fun getInstance(context: Context): ImageLoader { - instance?.let { return it } - - synchronized(this) { - return ImageLoader.Builder(context) - .memoryCachePolicy(CachePolicy.DISABLED) - .diskCachePolicy(CachePolicy.DISABLED) - .components { add(SvgDecoder.Factory()) } - .build().also { instance = it } - } - } - } -} +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.browser.icons.decoder + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Bitmap.Config.ARGB_8888 +import android.graphics.Canvas +import android.graphics.RectF +import androidx.core.graphics.createBitmap +import com.caverock.androidsvg.SVG +import com.caverock.androidsvg.SVGParseException +import mozilla.components.support.base.log.logger.Logger +import mozilla.components.support.images.DesiredSize +import mozilla.components.support.images.decoder.ImageDecoder + +/** + * [ImageDecoder] that will use the AndroidSVG in order to decode the byte data. + * + * The code is largely borrowed from [coil-svg](https://github.com/coil-kt/coil/blob/2.4.0/coil-svg/src/main/java/coil/decode/SvgDecoder.kt) + * with some fixed options. + */ +class SvgIconDecoder(val context: Context) : ImageDecoder { + private val logger = Logger("SvgIconDecoder") + + override fun decode(data: ByteArray, desiredSize: DesiredSize): Bitmap? = + try { + val svg = SVG.getFromInputStream(data.inputStream()) + + val svgWidth: Float + val svgHeight: Float + val viewBox: RectF? = svg.documentViewBox + if (viewBox != null) { + svgWidth = viewBox.width() + svgHeight = viewBox.height() + } else { + svgWidth = svg.documentWidth + svgHeight = svg.documentHeight + } + + var bitmapWidth = desiredSize.targetSize + var bitmapHeight = desiredSize.targetSize + + // Scale the bitmap to SVG maintaining the aspect ratio + if (svgWidth > 0 && svgHeight > 0) { + val widthPercent = bitmapWidth / svgWidth.toDouble() + val heightPercent = bitmapHeight / svgHeight.toDouble() + val multiplier = minOf(widthPercent, heightPercent) + + bitmapWidth = (multiplier * svgWidth).toInt() + bitmapHeight = (multiplier * svgHeight).toInt() + } + + // Set the SVG's view box to enable scaling if it is not set. + if (viewBox == null && svgWidth > 0 && svgHeight > 0) { + svg.setDocumentViewBox(0f, 0f, svgWidth, svgHeight) + } + + svg.setDocumentWidth("100%") + svg.setDocumentHeight("100%") + + val bitmap = createBitmap(bitmapWidth, bitmapHeight, ARGB_8888) + svg.renderToCanvas(Canvas(bitmap)) + + bitmap + } catch (e: SVGParseException) { + logger.error("Failed to parse the byte data to SVG") + null + } catch (e: OutOfMemoryError) { + logger.error("Failed to decode the byte data due to OutOfMemoryError") + null + } +} diff --git a/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt b/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt index 1114f8aa9fdc..5101eea3f586 100644 --- a/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt +++ b/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt @@ -26,7 +26,7 @@ object Versions { const val jacoco = "0.8.11" const val okhttp = "4.12.0" const val okio = "3.8.0" - const val coil = "2.4.0" + const val androidsvg = "1.4" const val android_gradle_plugin = "8.2.2" @@ -211,14 +211,7 @@ object ComponentsDependencies { const val thirdparty_sentry = "io.sentry:sentry-android:${Versions.sentry}" const val thirdparty_zxing = "com.google.zxing:core:${Versions.zxing}" const val thirdparty_disklrucache = "com.jakewharton:disklrucache:${Versions.disklrucache}" - /** - * ⚠️️ DO NOT use any NETWORK based operations provided by the Coil library. - * ⚠️️ The Coil library should be used for DECODING data only. - * - * Fenix is using SvgDecoder.kt for SVG decoding. However this dependency will also expose other - * API features that Fenix should not use. - */ - const val thirdparty_coil_svg = "io.coil-kt:coil-svg:${Versions.coil}" + const val thirdparty_androidsvg = "com.caverock:androidsvg-aar:${Versions.androidsvg}" const val firebase_messaging = "com.google.firebase:firebase-messaging:${Versions.Firebase.messaging}" } -- 2.11.4.GIT