Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add automatic HazeInputScale #427

Merged
merged 1 commit into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,19 @@ You can provide an input scale value which determines how much the content is sc
LargeTopAppBar(
// ...
modifier = Modifier.hazeChild(hazeState) {
inputScale = HazeInputScale.Fixed(0.5f)
inputScale = HazeInputScale.Auto
}
)
```

Using a value less than 1.0 **may** improve performance, at the sacrifice of quality and crispness. As always, run your own benchmarks as to whether this compromise is worth it.
`HazeInputScale` has a number of different options:

If you're looking for a good value to experiment with, `0.8` results in a reduction in total resolution of ~35%, while being visually imperceptible to most people (probably).
- `HazeInputScale.None`: Turns off input scaling (default)
- `HazeInputScale.Auto`: Turns on input scaling, with automatic values derived underneath.
- `HazeInputScale.Fixed(...)`: Turns on input scaling, using the value you pass in.

The minimum value I would realistically use is somewhere in the region of `0.5`, which results in the total pixel count of only 25% of the original content. This is likely to be visually different to no scaling, but depending on the styling parameters, it will be visually pleasing to the user.
When using a `Fixed` value, less than 1.0 **may** improve performance, at the sacrifice of quality and crispness. As always, run your own benchmarks as to whether this compromise is worth it.

If you're looking for a good value to experiment with, `0.66` results in a reduction in total resolution of ~55%, while being visually imperceptible to most people (probably).

The minimum value I would realistically use is somewhere in the region of `0.33`, which results in the total pixel count of only 11% of the original content. This is likely to be visually different to no scaling, but depending on the styling parameters, it will be visually pleasing to the user.
4 changes: 4 additions & 0 deletions haze/api/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ package dev.chrisbanes.haze {
field public static final dev.chrisbanes.haze.HazeInputScale.Companion Companion;
}

public static final class HazeInputScale.Auto implements dev.chrisbanes.haze.HazeInputScale {
field public static final dev.chrisbanes.haze.HazeInputScale.Auto INSTANCE;
}

public static final class HazeInputScale.Companion {
method public dev.chrisbanes.haze.HazeInputScale getDefault();
property @dev.chrisbanes.haze.ExperimentalHazeApi public final dev.chrisbanes.haze.HazeInputScale Default;
Expand Down
8 changes: 7 additions & 1 deletion haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChild.kt
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ sealed interface HazeInputScale {
*/
data object None : HazeInputScale

/**
* Automatic input scaling. Haze will attempt to use an appropriate input scale depending on
* the other settings which have been set. The values used underneath may change in the future.
*/
data object Auto : HazeInputScale

/**
* An input scale which uses a fixed scale factor.
*
Expand All @@ -175,7 +181,7 @@ sealed interface HazeInputScale {
companion object {
/**
* The default [HazeInputScale] value. Currently this resolves to [HazeInputScale.None] but
* this may change in the future.
* this may change in the future, probably to [HazeInputScale.Auto].
*/
@ExperimentalHazeApi
val Default: HazeInputScale get() = None
Expand Down
34 changes: 20 additions & 14 deletions haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChildNode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -259,24 +259,19 @@ class HazeChildNode(
}

override fun ContentDrawScope.draw() {
log(TAG) { "-> HazeChild. start draw()" }

require(!state.contentDrawing) {
"Layout nodes using Modifier.haze and Modifier.hazeChild can not be descendants of each other"
}

if (!isValid) {
// If we don't have any effects, just call drawContent and return early
drawContent()
log(TAG) { "-> HazeChild. end draw()" }
return
}
log(TAG) { "-> HazeChild. start draw()" }

val contentLayer = state.contentLayer
if (contentLayer != null && blurEnabled && canUseGraphicLayers()) {
drawEffectWithGraphicsLayer(contentLayer)
} else {
drawEffectWithScrim()
if (isValid) {
val contentLayer = state.contentLayer
if (contentLayer != null && blurEnabled && canUseGraphicLayers()) {
drawEffectWithGraphicsLayer(contentLayer)
} else {
drawEffectWithScrim()
}
}

// Finally we draw the content
Expand Down Expand Up @@ -535,9 +530,20 @@ internal data class RenderEffectParams(
)

@ExperimentalHazeApi
internal fun HazeChildNode.calculateInputScaleFactor(): Float = when (val s = inputScale) {
internal fun HazeChildNode.calculateInputScaleFactor(
blurRadius: Dp = resolveBlurRadius(),
): Float = when (val s = inputScale) {
HazeInputScale.None -> 1f
is HazeInputScale.Fixed -> s.scale
HazeInputScale.Auto -> {
when {
// For small blurRadius values, input scaling is very noticeable therefore we turn it off
blurRadius < 7.dp -> 1f
progressive != null -> 0.5f
mask != null -> 0.5f
else -> 0.3334f
}
}
}

@OptIn(ExperimentalHazeApi::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,11 @@ import dev.chrisbanes.haze.HazeInputScale

val Samples = listOf(
Sample("Scaffold") { ScaffoldSample(it) },
Sample("Scaffold (input scaled)") { ScaffoldSample(it, inputScale = HazeInputScale.Fixed(0.5f)) },
Sample("Scaffold (input scaled)") { ScaffoldSample(it, inputScale = HazeInputScale.Auto) },
Sample("Scaffold (progressive blur)") { ScaffoldSample(it, ScaffoldSampleMode.Progressive) },
Sample("Scaffold (progressive blur, input scaled)") {
ScaffoldSample(it, ScaffoldSampleMode.Progressive, HazeInputScale.Fixed(0.5f))
},
Sample("Scaffold (progressive blur, input scaled)") { ScaffoldSample(it, ScaffoldSampleMode.Progressive, HazeInputScale.Auto) },
Sample("Scaffold (masked)") { ScaffoldSample(it, ScaffoldSampleMode.Mask) },
Sample("Scaffold (masked, input scaled)") { ScaffoldSample(it, ScaffoldSampleMode.Mask, HazeInputScale.Auto) },
Sample("Credit Card") { CreditCardSample(it) },
Sample("Images List") { ImagesList(it) },
Sample("List over Image") { ListOverImage(it) },
Expand Down