fix(glass): reuse CORS wallpaper sources (#640)

This commit is contained in:
InfinityPacer
2026-08-04 16:35:17 +08:00
committed by GitHub
parent a545f88b3c
commit afc95ad990
6 changed files with 92 additions and 10 deletions

View File

@@ -154,6 +154,7 @@ const globalSettingsStore = useGlobalSettingsStore()
const backgroundImages = ref<string[]>([])
const backgroundLayers = ref(createLoginBackgroundLayers())
const backgroundDisplayImages = ref<Record<string, string>>({})
const backgroundCorsReady = ref<Record<string, boolean>>({})
const backgroundToneProfiles = ref<Record<string, GlassWallpaperToneProfile>>({})
const activeImageIndex = ref(0)
const previousImageIndex = ref<number | null>(null)
@@ -302,13 +303,25 @@ function getBackgroundLayerStyle(layer: LoginBackgroundLayer) {
const appearance = effectiveGlassSettings.value.glassAppearance
const materialExposure = appearance === 'frosted' ? 0.82 : appearance === 'tinted' ? 0.85 : 0.86
const displayUrl = isGlassTheme.value ? getPreparedBackgroundImage(layer.url) : layer.url
const usesCorsImageElement = isGlassTheme.value && Object.hasOwn(backgroundDisplayImages.value, layer.url)
return {
'backgroundImage': displayUrl ? `url(${displayUrl})` : undefined,
'backgroundImage': !usesCorsImageElement && displayUrl ? `url(${displayUrl})` : undefined,
'--glass-wallpaper-brightness': String(materialExposure * profile.exposure),
}
}
/** 玻璃可见层与 tone/WebGL 使用同一图片请求模式,避免 CSS 再创建无 Origin 的缓存变体。 */
function getBackgroundLayerImageSource(layer: LoginBackgroundLayer) {
if (!isGlassTheme.value || !Object.hasOwn(backgroundDisplayImages.value, layer.url)) return ''
return getPreparedBackgroundImage(layer.url)
}
function getBackgroundLayerCrossOrigin(layer: LoginBackgroundLayer) {
return backgroundCorsReady.value[layer.url] ? 'anonymous' : undefined
}
const needsStableFixedBackdrop = isChromiumFixedShellBackplateBrowser()
const fixedShellBackplateLayers = computed<readonly GlassFixedShellBackplateLayer[]>(() => {
const hasWallpaper = renderedBackgroundLayers.value.some(layer => Boolean(layer.url))
@@ -327,6 +340,8 @@ const fixedShellBackplateLayers = computed<readonly GlassFixedShellBackplateLaye
return renderedBackgroundLayers.value.map(layer => ({
...layer,
crossOrigin: getBackgroundLayerCrossOrigin(layer),
src: getBackgroundLayerImageSource(layer),
style: getBackgroundLayerStyle(layer),
}))
})
@@ -711,6 +726,10 @@ async function preloadBackgroundCandidate(imageUrl: string) {
...backgroundDisplayImages.value,
[imageUrl]: opticalUrl,
}
backgroundCorsReady.value = {
...backgroundCorsReady.value,
[imageUrl]: true,
}
recordGlassLaunchTiming('wallpaper-source-ready', imageUrl)
return true
}
@@ -719,6 +738,10 @@ async function preloadBackgroundCandidate(imageUrl: string) {
...backgroundDisplayImages.value,
[imageUrl]: imageUrl,
}
backgroundCorsReady.value = {
...backgroundCorsReady.value,
[imageUrl]: false,
}
const ready = await preloadImage(imageUrl)
recordGlassLaunchTiming(ready ? 'wallpaper-source-ready' : 'wallpaper-source-failed', imageUrl)
@@ -1137,7 +1160,17 @@ onUnmounted(() => {
class="background-image"
:class="layer.role"
:style="getBackgroundLayerStyle(layer)"
/>
>
<img
v-if="getBackgroundLayerImageSource(layer)"
class="background-image__source"
:crossorigin="getBackgroundLayerCrossOrigin(layer)"
:src="getBackgroundLayerImageSource(layer)"
alt=""
aria-hidden="true"
draggable="false"
/>
</div>
<!-- 全局磨砂层 -->
<div v-if="shouldRenderGlobalBlurLayer" class="global-blur-layer"></div>
</div>
@@ -1238,6 +1271,16 @@ onUnmounted(() => {
}
}
.background-image__source {
position: absolute;
display: block;
block-size: 100%;
inline-size: 100%;
inset: 0;
object-fit: cover;
pointer-events: none;
}
.background-container.is-transparent-theme .background-image.active {
opacity: var(--transparent-background-poster-opacity, 1);
}

View File

@@ -103,6 +103,7 @@ async function goPlay() {
@keyup.enter="goPlay"
@keyup.space="goPlay"
>
<!-- 媒体服务器图片统一采用匿名 CORS避免同一代理资源分裂为两种请求与缓存模式Safari 普通 dev 可能重复请求PWA 下由图片缓存路由统一处理 -->
<VImg
:src="imageUrl"
crossorigin="anonymous"

View File

@@ -63,6 +63,7 @@ async function goPlay(isHovering: boolean | null = false) {
'ring-1': isImageLoaded,
}"
>
<!-- 媒体服务器图片统一采用匿名 CORS避免同一代理资源分裂为两种请求与缓存模式Safari 普通 dev 可能重复请求PWA 下由图片缓存路由统一处理 -->
<VImg
aspect-ratio="2/3"
:src="getImgUrl"

View File

@@ -32,7 +32,17 @@ const transitionStyle = computed(() => ({
:class="`is-${layer.role}`"
:data-backplate-slot="layer.key"
>
<div class="glass-fixed-shell-backplate__wallpaper" :style="layer.style" />
<div class="glass-fixed-shell-backplate__wallpaper" :style="layer.style">
<img
v-if="layer.src"
class="glass-fixed-shell-backplate__source"
:crossorigin="layer.crossOrigin"
:src="layer.src"
alt=""
aria-hidden="true"
draggable="false"
/>
</div>
</div>
</div>
@@ -51,7 +61,17 @@ const transitionStyle = computed(() => ({
:class="`is-${layer.role}`"
:data-backplate-slot="layer.key"
>
<div class="glass-fixed-shell-backplate__wallpaper" :style="layer.style" />
<div class="glass-fixed-shell-backplate__wallpaper" :style="layer.style">
<img
v-if="layer.src"
class="glass-fixed-shell-backplate__source"
:crossorigin="layer.crossOrigin"
:src="layer.src"
alt=""
aria-hidden="true"
draggable="false"
/>
</div>
</div>
</div>
</template>
@@ -160,6 +180,16 @@ const transitionStyle = computed(() => ({
}
}
.glass-fixed-shell-backplate__source {
position: absolute;
display: block;
block-size: 100%;
inline-size: 100%;
inset: 0;
object-fit: cover;
pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
.glass-fixed-shell-backplate,
.glass-fixed-shell-backplate__layer {

View File

@@ -7,8 +7,9 @@ const initialLayers: readonly GlassFixedShellBackplateLayer[] = [
{
key: 'front',
role: 'active',
crossOrigin: 'anonymous',
src: '/wallpaper-current.jpg',
style: {
'backgroundImage': 'url(/wallpaper-current.jpg)',
'--glass-wallpaper-brightness': '0.82',
},
url: '/wallpaper-current.jpg',
@@ -16,8 +17,9 @@ const initialLayers: readonly GlassFixedShellBackplateLayer[] = [
{
key: 'back',
role: 'standby',
crossOrigin: 'anonymous',
src: '/wallpaper-next.jpg',
style: {
'backgroundImage': 'url(/wallpaper-next.jpg)',
'--glass-wallpaper-brightness': '0.76',
},
url: '/wallpaper-next.jpg',
@@ -38,9 +40,10 @@ describe('GlassFixedShellBackplate', () => {
expect(wrapper.findAll('[data-backplate-surface="main"] [data-backplate-slot]')).toHaveLength(2)
expect(wrapper.find('[data-backplate-slot="front"]').classes()).toContain('is-active')
expect(wrapper.find('[data-backplate-slot="back"]').classes()).toContain('is-standby')
expect(
(wrapper.find('[data-backplate-slot="front"] > div').element as HTMLElement).style.backgroundImage,
).toContain('/wallpaper-current.jpg')
expect(wrapper.find('[data-backplate-slot="front"] img').attributes()).toMatchObject({
crossorigin: 'anonymous',
src: '/wallpaper-current.jpg',
})
expect(wrapper.find('[data-backplate-surface="main"]').attributes('style')).toContain(
'--glass-fixed-shell-transition-duration: 1500ms',
)

View File

@@ -3,7 +3,11 @@ import type { ThemeCustomizerGlassAppearance, ThemeCustomizerGlassQuality } from
import type { LoginBackgroundLayer } from '@/utils/loginPresentation'
export interface GlassFixedShellBackplateLayer extends LoginBackgroundLayer {
/** 当前槽位直接采样壁纸所需的背景图与色调变量。 */
/** 与 tone/WebGL 一致的图片请求模式CORS 不可用时省略并使用普通图片回退。 */
crossOrigin?: 'anonymous'
/** 已完成首图准备、可直接进入稳定背板槽位的图片地址。 */
src: string
/** 当前槽位直接采样壁纸时叠加的色调变量。 */
style: StyleValue
}