11package com.rngooglemapsplus
22
33import android.graphics.Bitmap
4+ import android.graphics.BitmapFactory
45import android.graphics.Canvas
6+ import android.graphics.Typeface
57import android.util.Base64
68import android.util.LruCache
79import androidx.core.graphics.createBitmap
810import com.caverock.androidsvg.SVG
911import com.caverock.androidsvg.SVGExternalFileResolver
1012import com.facebook.react.uimanager.PixelUtil.dpToPx
13+ import com.facebook.react.uimanager.ThemedReactContext
1114import com.google.android.gms.maps.model.BitmapDescriptor
1215import com.google.android.gms.maps.model.BitmapDescriptorFactory
1316import com.google.android.gms.maps.model.Marker
@@ -22,10 +25,13 @@ import kotlinx.coroutines.SupervisorJob
2225import kotlinx.coroutines.ensureActive
2326import kotlinx.coroutines.launch
2427import kotlinx.coroutines.withContext
28+ import java.net.HttpURLConnection
29+ import java.net.URL
2530import java.net.URLDecoder
2631import kotlin.coroutines.coroutineContext
2732
2833class MapMarkerBuilder (
34+ val context : ThemedReactContext ,
2935 private val scope : CoroutineScope = CoroutineScope (SupervisorJob () + Dispatchers .Default ),
3036) {
3137 private val iconCache =
@@ -39,6 +45,7 @@ class MapMarkerBuilder(
3945 private val jobsById = mutableMapOf<String , Job >()
4046
4147 init {
48+ // / TODO: refactor with androidsvg 1.5 release
4249 SVG .registerExternalFileResolver(
4350 object : SVGExternalFileResolver () {
4451 override fun resolveImage (filename : String? ): Bitmap ? {
@@ -64,11 +71,70 @@ class MapMarkerBuilder(
6471 }
6572 }
6673
74+ filename.startsWith(" http://" ) || filename.startsWith(" https://" ) -> {
75+ val conn =
76+ (URL (filename).openConnection() as HttpURLConnection ).apply {
77+ connectTimeout = 5000
78+ readTimeout = 5000
79+ requestMethod = " GET"
80+ instanceFollowRedirects = true
81+ }
82+ conn.connect()
83+
84+ val contentType = conn.contentType ? : " "
85+ val result =
86+ if (contentType.contains(" svg" ) || filename.endsWith(" .svg" )) {
87+ val svgText = conn.inputStream.bufferedReader().use { it.readText() }
88+ val innerSvg = SVG .getFromString(svgText)
89+ val w = innerSvg.documentWidth.takeIf { it > 0 } ? : 128f
90+ val h = innerSvg.documentHeight.takeIf { it > 0 } ? : 128f
91+ val bmp = createBitmap(w.toInt(), h.toInt())
92+ val canvas = Canvas (bmp)
93+ innerSvg.renderToCanvas(canvas)
94+ bmp
95+ } else {
96+ conn.inputStream.use { BitmapFactory .decodeStream(it) }
97+ }
98+
99+ conn.disconnect()
100+ result
101+ }
102+
67103 else -> null
68104 }
69105 }.getOrNull()
70106 }
71107
108+ override fun resolveFont (
109+ fontFamily : String? ,
110+ fontWeight : Int ,
111+ fontStyle : String? ,
112+ ): Typeface ? {
113+ if (fontFamily.isNullOrBlank()) return null
114+
115+ return runCatching {
116+ val assetManager = context.assets
117+
118+ val candidates =
119+ listOf (
120+ " fonts/$fontFamily .ttf" ,
121+ " fonts/$fontFamily .otf" ,
122+ )
123+
124+ for (path in candidates) {
125+ try {
126+ return Typeface .createFromAsset(assetManager, path)
127+ } catch (_: Throwable ) {
128+ // / ignore
129+ }
130+ }
131+
132+ Typeface .create(fontFamily, Typeface .NORMAL )
133+ }.getOrElse {
134+ Typeface .create(fontFamily, fontWeight)
135+ }
136+ }
137+
72138 override fun isFormatSupported (mimeType : String? ): Boolean = mimeType?.startsWith(" image/" ) == true
73139 },
74140 )
0 commit comments