Skip to content

Commit c775fa7

Browse files
committed
Fixed crash for zero width images
1 parent 67b521a commit c775fa7

File tree

2 files changed

+61
-26
lines changed

2 files changed

+61
-26
lines changed

app/src/main/java/com/nononsenseapps/feeder/ui/compose/text/HtmlToComposable.kt

+8-3
Original file line numberDiff line numberDiff line change
@@ -1260,8 +1260,8 @@ internal fun getImageSource(
12601260
srcSet = element.attr("srcset") ?: "",
12611261
absSrc = element.attr("abs:src") ?: "",
12621262
dataImgUrl = element.attr("data-img-url") ?: "",
1263-
width = element.attr("width")?.toIntOrNull(),
1264-
height = element.attr("height")?.toIntOrNull(),
1263+
width = element.attr("width").toIntOrNull(),
1264+
height = element.attr("height").toIntOrNull(),
12651265
)
12661266

12671267
internal class ImageCandidates(
@@ -1272,7 +1272,8 @@ internal class ImageCandidates(
12721272
val width: Int?,
12731273
val height: Int?,
12741274
) {
1275-
val hasImage: Boolean = srcSet.isNotBlank() || absSrc.isNotBlank() || dataImgUrl.isNotBlank()
1275+
// Explicitly width/height = 0 means no image
1276+
val hasImage: Boolean = width != 0 && height != 0 && (srcSet.isNotBlank() || absSrc.isNotBlank() || dataImgUrl.isNotBlank())
12761277
val notHasImage: Boolean = !hasImage
12771278

12781279
fun getBestImageForMaxSize(
@@ -1301,6 +1302,10 @@ internal class ImageCandidates(
13011302
when {
13021303
descriptor.endsWith("w", ignoreCase = true) -> {
13031304
val width = descriptor.substringBefore("w").toFloat()
1305+
if (width < 1.0f) {
1306+
return@fold acc
1307+
}
1308+
13041309
val ratio = width / maxWidth.toFloat()
13051310

13061311
ratio to

app/src/test/java/com/nononsenseapps/feeder/ui/compose/text/HtmlToComposableUnitTest.kt

+53-23
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,54 @@ class HtmlToComposableUnitTest {
1616

1717
@Before
1818
fun setup() {
19-
every { element.attr("width") } returns null
20-
every { element.attr("height") } returns null
21-
every { element.attr("data-img-url") } returns null
19+
every { element.attr("width") } returns ""
20+
every { element.attr("height") } returns ""
21+
every { element.attr("data-img-url") } returns ""
2222
}
2323

2424
@Test
2525
fun findImageSrcWithNoSrc() {
26-
every { element.attr("srcset") } returns null
27-
every { element.attr("abs:src") } returns null
26+
every { element.attr("srcset") } returns ""
27+
every { element.attr("abs:src") } returns ""
2828

2929
val result = getImageSource("http://foo", element)
3030

3131
assertFalse(result.hasImage)
3232
}
3333

34+
@Test
35+
fun findImageOnlySrcWithZeroPixels() {
36+
every { element.attr("srcset") } returns ""
37+
every { element.attr("abs:src") } returns "http://foo/image.jpg"
38+
every { element.attr("width") } returns "0"
39+
every { element.attr("height") } returns "0"
40+
41+
val result = getImageSource("http://foo", element)
42+
43+
assertTrue(result.notHasImage)
44+
}
45+
46+
@Test
47+
fun findImageBestZeroPixelSrcSetIsNoImage() {
48+
every { element.attr("srcset") } returns "header640.png 0w"
49+
every { element.attr("abs:src") } returns ""
50+
every { element.attr("width") } returns ""
51+
every { element.attr("height") } returns ""
52+
53+
val result = getImageSource("http://foo", element)
54+
55+
assertTrue(result.hasImage)
56+
57+
val maxSize = 1
58+
val best = result.getBestImageForMaxSize(maxSize, 1.0f)
59+
assertTrue("$best should be NoImageCandidate") {
60+
best is NoImageCandidate
61+
}
62+
}
63+
3464
@Test
3565
fun findImageOnlySrc() {
36-
every { element.attr("srcset") } returns null
66+
every { element.attr("srcset") } returns ""
3767
every { element.attr("abs:src") } returns "http://foo/image.jpg"
3868

3969
val result = getImageSource("http://foo", element)
@@ -46,7 +76,7 @@ class HtmlToComposableUnitTest {
4676
@Test
4777
fun findImageOnlySingleSrcSet() {
4878
every { element.attr("srcset") } returns "image.jpg"
49-
every { element.attr("abs:src") } returns null
79+
every { element.attr("abs:src") } returns ""
5080

5181
val result = getImageSource("http://foo", element)
5282

@@ -58,7 +88,7 @@ class HtmlToComposableUnitTest {
5888
@Test
5989
fun findImageBestMinSrcSet() {
6090
every { element.attr("srcset") } returns "header640.png 640w, header960.png 960w, header2x.png 2x, header3.0x.png 3.0x, header.png"
61-
every { element.attr("abs:src") } returns null
91+
every { element.attr("abs:src") } returns ""
6292

6393
val result = getImageSource("http://foo", element)
6494

@@ -72,7 +102,7 @@ class HtmlToComposableUnitTest {
72102
@Test
73103
fun findImageBest640SrcSet() {
74104
every { element.attr("srcset") } returns "header640.png 640w, header960.png 960w, header2x.png 2x, header3.0x.png 3.0x, header.png"
75-
every { element.attr("abs:src") } returns null
105+
every { element.attr("abs:src") } returns ""
76106

77107
val result = getImageSource("http://foo", element)
78108

@@ -86,7 +116,7 @@ class HtmlToComposableUnitTest {
86116
@Test
87117
fun findImageBest960SrcSet() {
88118
every { element.attr("srcset") } returns "header640.png 640w, header960.png 960w, header2x.png 2x, header3.0x.png 3.0x, header.png"
89-
every { element.attr("abs:src") } returns null
119+
every { element.attr("abs:src") } returns ""
90120

91121
val result = getImageSource("http://foo", element)
92122

@@ -100,7 +130,7 @@ class HtmlToComposableUnitTest {
100130
@Test
101131
fun findImageBest650SrcSet() {
102132
every { element.attr("srcset") } returns "header640.png 640w, header960.png 960w, header2x.png 2x, header3.0x.png 3.0x, header.png"
103-
every { element.attr("abs:src") } returns null
133+
every { element.attr("abs:src") } returns ""
104134

105135
val result = getImageSource("http://foo", element)
106136

@@ -114,7 +144,7 @@ class HtmlToComposableUnitTest {
114144
@Test
115145
fun findImageBest950SrcSet() {
116146
every { element.attr("srcset") } returns "header640.png 640w, header960.png 960w, header2x.png 2x, header3.0x.png 3.0x, header.png"
117-
every { element.attr("abs:src") } returns null
147+
every { element.attr("abs:src") } returns ""
118148

119149
val result = getImageSource("http://foo", element)
120150

@@ -128,7 +158,7 @@ class HtmlToComposableUnitTest {
128158
@Test
129159
fun findImageBest1500SrcSet() {
130160
every { element.attr("srcset") } returns "header640.png 640w, header960.png 960w, header2x.png 2x, header3.0x.png 3.0x, header.png"
131-
every { element.attr("abs:src") } returns null
161+
every { element.attr("abs:src") } returns ""
132162

133163
val result = getImageSource("http://foo", element)
134164

@@ -142,7 +172,7 @@ class HtmlToComposableUnitTest {
142172
@Test
143173
fun findImageBest3xSrcSet() {
144174
every { element.attr("srcset") } returns "header2x.png 2x, header3.0x.png 3.0x, header.png"
145-
every { element.attr("abs:src") } returns null
175+
every { element.attr("abs:src") } returns ""
146176

147177
val result = getImageSource("http://foo", element)
148178

@@ -156,7 +186,7 @@ class HtmlToComposableUnitTest {
156186
@Test
157187
fun findImageBest1xSrcSet() {
158188
every { element.attr("srcset") } returns "header2x.png 2x, header3.0x.png 3.0x, header.png"
159-
every { element.attr("abs:src") } returns null
189+
every { element.attr("abs:src") } returns ""
160190

161191
val result = getImageSource("http://foo", element)
162192

@@ -220,8 +250,8 @@ class HtmlToComposableUnitTest {
220250
every {
221251
element.attr("abs:src")
222252
} returns "https://duet-cdn.vox-cdn.com/thumbor/184x0:2614x1535/2400x1600/filters:focal(1847x240:1848x241):format(webp)/cdn.vox-cdn.com/uploads/chorus_asset/file/24842461/Screenshot_2023_08_10_at_12.22.58_PM.png"
223-
every { element.attr("width") } returns null
224-
every { element.attr("height") } returns null
253+
every { element.attr("width") } returns ""
254+
every { element.attr("height") } returns ""
225255

226256
val result = getImageSource("https://www.politico.eu/feed/", element)
227257

@@ -246,12 +276,12 @@ class HtmlToComposableUnitTest {
246276
} returns "https://static1.xdaimages.com/wordpress/wp-content/uploads/2023/12/onedrive-app-for-microsoft-teams.png"
247277
every {
248278
element.attr("srcset")
249-
} returns null
279+
} returns ""
250280
every {
251281
element.attr("abs:src")
252-
} returns null
253-
every { element.attr("width") } returns null
254-
every { element.attr("height") } returns null
282+
} returns ""
283+
every { element.attr("width") } returns ""
284+
every { element.attr("height") } returns ""
255285

256286
val result = getImageSource("https://www.xda-developers.com", element)
257287

@@ -273,8 +303,8 @@ class HtmlToComposableUnitTest {
273303
fun noSourcesMeansEmptyResult() {
274304
every { element.attr("srcset") } returns ""
275305
every { element.attr("abs:src") } returns ""
276-
every { element.attr("width") } returns null
277-
every { element.attr("height") } returns null
306+
every { element.attr("width") } returns ""
307+
every { element.attr("height") } returns ""
278308

279309
val result = getImageSource("https://www.politico.eu/feed/", element)
280310

0 commit comments

Comments
 (0)