(url)
| 263 | } |
| 264 | |
| 265 | async function loadIcon(url) { |
| 266 | const img = new Image(); |
| 267 | const isOwn = url.startsWith(ICON_PREFIX); |
| 268 | const src = isOwn ? url.slice(extensionOrigin.length) // must be a relative path in Firefox Android |
| 269 | : url.startsWith('data:') ? url |
| 270 | : makeDataUri(url[0] === 'i' ? url : await loadStorageCache(url)); |
| 271 | if (!src) { |
| 272 | // not saving to iconCache[url] because it may be a temporary network problem |
| 273 | return; |
| 274 | } |
| 275 | img.src = src; |
| 276 | if (!await new Promise((resolve) => { |
| 277 | img.onload = resolve; |
| 278 | img.onerror = () => resolve(); |
| 279 | })) { |
| 280 | return; |
| 281 | } |
| 282 | let res; |
| 283 | let maxSize = !isOwn && (2 * 38); // dashboard icon size for 2xDPI |
| 284 | let { width, height } = img; |
| 285 | if (!width || !height) { // FF reports 0 for SVG |
| 286 | iconCache[url] = url; |
| 287 | return url; |
| 288 | } |
| 289 | if (maxSize && (width > maxSize || height > maxSize)) { |
| 290 | maxSize /= width > height ? width : height; |
| 291 | width = Math.round(width * maxSize); |
| 292 | height = Math.round(height * maxSize); |
| 293 | } |
| 294 | const canvas = document.createElement('canvas'); |
| 295 | const ctx = canvas.getContext('2d'); |
| 296 | canvas.width = width; |
| 297 | canvas.height = height; |
| 298 | ctx.drawImage(img, 0, 0, width, height); |
| 299 | try { |
| 300 | res = canvas.toDataURL(); |
| 301 | if (isOwn) iconDataCache[url] = ctx.getImageData(0, 0, width, height); |
| 302 | } catch (err) { |
| 303 | res = url; |
| 304 | } |
| 305 | iconCache[url] = res; |
| 306 | return res; |
| 307 | } |
| 308 | |
| 309 | async function loadStorageCache(url) { |
| 310 | return await storage[S_CACHE].getOne(url) |
no test coverage detected