From f75f2598a3f42c1cd91eb09a7b1dfa1462d508b3 Mon Sep 17 00:00:00 2001 From: w Date: Mon, 17 Aug 2026 10:08:09 -0700 Subject: [PATCH] Fix fit height to in new renderer and bump webgpuviewer (#3801) --- .../ui/reader/viewer/webgpu/WebGpuViewer.kt | 64 +++++++++++++++++++ gradle/libs.versions.toml | 2 +- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webgpu/WebGpuViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webgpu/WebGpuViewer.kt index 627c4d481..25fffcdae 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webgpu/WebGpuViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webgpu/WebGpuViewer.kt @@ -884,6 +884,7 @@ open class WebGpuViewer( oldImagePage.cleanup() } applyWideZoomIfNeeded(page) + applyFitModeAnchor(page.imagePage) pager.state.invalidate() } else { if (pageInCache(page)) page.state = PageState.IDLE @@ -1018,6 +1019,69 @@ open class WebGpuViewer( } } + private fun applyFitModeAnchor(page: ImagePage) { + if (page.homeScaleOverride != null) return + + val scaleType = config.imageScaleType + if (scaleType != 3 && scaleType != 4 && scaleType != 5) return + + val image = page.image ?: return + if (image.position != Image.Position.SINGLE) return + + val screenW = pager.state.width + val screenH = pager.state.height + if (screenW <= 0 || screenH <= 0) return + + val w = page.trimWidth.toFloat() + val h = page.trimHeight.toFloat() + if (w <= 0f || h <= 0f) return + + val cutoutTopPx = pager.state.cutoutTopPx + val contentW = screenW.toFloat() + val contentH = if (pager.state.avoidCutout && cutoutTopPx > 0f) screenH - cutoutTopPx else screenH.toFloat() + + val homeScale = when (scaleType) { + 3 -> contentW / w + 4 -> contentH / h + else -> 1f // original size + }.coerceAtLeast(0.01f) + page.homeScaleOverride = homeScale + + if (scaleType == 5) { // original size + val minScaleComputed = minOf(contentW / page.width, contentH / page.height).coerceAtLeast(0.01f) + if (homeScale < minScaleComputed) { + page.minScale = homeScale + } + } + + // zoom start for fit height/original size + page.homeXOverride = if (scaleType == 4 || scaleType == 5) { + val maxX = maxOf(0f, (page.width.toFloat() / screenW - 1f / homeScale) / 2f) + when (config.imageZoomType) { + ZoomStartPosition.LEFT -> maxX + ZoomStartPosition.RIGHT -> -maxX + ZoomStartPosition.CENTER -> 0f + } + } else { + null + } + + // push below cutout for fit width/original size + val trimTop = image.trim?.top ?: 0 + val imageTopY = (screenH - page.height * homeScale) / 2f + val trimTopY = imageTopY + trimTop * homeScale + page.homeYOverride = if ((scaleType == 3 || scaleType == 5) && h * homeScale > screenH) { + val target = if (pager.state.avoidCutout && cutoutTopPx > 0f) { + if (pager.state.alwaysAvoidCutout) cutoutTopPx / 2f else cutoutTopPx + } else { + 0f + } + maxOf(0f, (target - trimTopY) / (homeScale * screenH)) + } else { + null + } + } + /** * Queue a page for decoding. If prioritize=true, moves existing queued page to front. */ diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4be8a4699..23278e651 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -76,7 +76,7 @@ swipe = "1.3.0" tapmoc = "0.4.2" unifile = "08f224c8f9" voyager = "2.2.21-1.10.3" -webgpuviewer = "25" +webgpuviewer = "28" xmlutil = "1.0.2" [libraries]