()
| 5 | const COLOR_SCHEME_META_SELECTOR = 'meta[name="color-scheme"]'; |
| 6 | |
| 7 | function hasBuiltInDarkTheme() { |
| 8 | const rootStyle = getComputedStyle(document.documentElement); |
| 9 | if (rootStyle.filter.includes('invert(1)') || rootStyle.colorScheme === 'dark') { |
| 10 | return true; |
| 11 | } |
| 12 | |
| 13 | const CELL_SIZE = 256; |
| 14 | const MAX_ROW_COUNT = 4; |
| 15 | const winWidth = innerWidth; |
| 16 | const winHeight = innerHeight; |
| 17 | const stepX = Math.floor(winWidth / Math.min(MAX_ROW_COUNT, Math.ceil(winWidth / CELL_SIZE))); |
| 18 | const stepY = Math.floor(winHeight / Math.min(MAX_ROW_COUNT, Math.ceil(winHeight / CELL_SIZE))); |
| 19 | |
| 20 | const processedElements = new Set<Element>(); |
| 21 | |
| 22 | for (let y = Math.floor(stepY / 2); y < winHeight; y += stepY) { |
| 23 | for (let x = Math.floor(stepX / 2); x < winWidth; x += stepX) { |
| 24 | const element = document.elementFromPoint(x, y); |
| 25 | if (!element || processedElements.has(element) || element.tagName.toLocaleLowerCase() === 'img') { |
| 26 | continue; |
| 27 | } |
| 28 | processedElements.add(element); |
| 29 | const style = element === document.documentElement ? rootStyle : getComputedStyle(element); |
| 30 | const bgColor = parseColorWithCache(style.backgroundColor); |
| 31 | if (!bgColor) { |
| 32 | return false; |
| 33 | } |
| 34 | if (bgColor.r === 24 && bgColor.g === 26 && bgColor.b === 27) { |
| 35 | // For some websites changes to CSSStyleSheet.disabled and HTMLStyleElement.textContent |
| 36 | // are not being applied synchronously. For example https://zorin.com/ |
| 37 | // Probably a browser bug. Treat as not having a dark theme. |
| 38 | return false; |
| 39 | } |
| 40 | if (bgColor.a === 1) { |
| 41 | const bgLightness = getSRGBLightness(bgColor.r, bgColor.g, bgColor.b); |
| 42 | if (bgLightness > 0.6) { |
| 43 | return false; |
| 44 | } |
| 45 | } else { |
| 46 | const textColor = parseColorWithCache(style.color); |
| 47 | if (!textColor) { |
| 48 | return false; |
| 49 | } |
| 50 | const textLightness = getSRGBLightness(textColor.r, textColor.g, textColor.b); |
| 51 | if (textLightness < 0.4) { |
| 52 | return false; |
| 53 | } |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | const rootColor = parseColorWithCache(rootStyle.backgroundColor); |
| 59 | if (!rootColor) { |
| 60 | return false; |
| 61 | } |
| 62 | |
| 63 | const bodyColor = document.body ? parseColorWithCache(getComputedStyle(document.body).backgroundColor) : {r: 0, g: 0, b: 0, a: 0}; |
| 64 | if (!bodyColor) { |
no test coverage detected