Skip to content

Commit

Permalink
Improve HazeInputScale API
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbanes committed Nov 28, 2024
1 parent e9732c1 commit 334b6c2
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 20 deletions.
6 changes: 3 additions & 3 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ LargeTopAppBar(

!!! warning "Performance of Progressive"

Please be aware that using progressive blurring does come with a performance cost. Please see the [Performance](performance.md) page for up-to-date benchmarks.
Please be aware that using progressive blurring does come with a performance cost. Please see the [Performance](performance.md) page for up-to-date benchmarks.

As a quick summary: on Android SDK 33+ and other platforms, the cost is about 25% more than non-progressive. On Android SDK 32 it is about 2x. If performance is critical, you may wish to look at the masking functionality below.

## Masking
Expand Down Expand Up @@ -133,7 +133,7 @@ You can provide an input scale value which determines how much the content is sc
LargeTopAppBar(
// ...
modifier = Modifier.hazeChild(hazeState) {
inputScale = 0.5f
inputScale = HazeInputScale.Fixed(0.5f)
}
)
```
Expand Down
33 changes: 27 additions & 6 deletions haze/api/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package dev.chrisbanes.haze {
method public boolean getBlurEnabled();
method public float getBlurRadius();
method public dev.chrisbanes.haze.HazeTint getFallbackTint();
method public float getInputScale();
method public dev.chrisbanes.haze.HazeInputScale getInputScale();
method public androidx.compose.ui.graphics.Brush? getMask();
method public float getNoiseFactor();
method public dev.chrisbanes.haze.HazeProgressive? getProgressive();
Expand All @@ -33,7 +33,7 @@ package dev.chrisbanes.haze {
method public void setBlurEnabled(boolean);
method public void setBlurRadius(float);
method public void setFallbackTint(dev.chrisbanes.haze.HazeTint);
method public void setInputScale(float);
method public void setInputScale(dev.chrisbanes.haze.HazeInputScale);
method public void setMask(androidx.compose.ui.graphics.Brush?);
method public void setNoiseFactor(float);
method public void setProgressive(dev.chrisbanes.haze.HazeProgressive?);
Expand All @@ -46,7 +46,7 @@ package dev.chrisbanes.haze {
property public boolean blurEnabled;
property public float blurRadius;
property public dev.chrisbanes.haze.HazeTint fallbackTint;
property public float inputScale;
property public dev.chrisbanes.haze.HazeInputScale inputScale;
property public androidx.compose.ui.graphics.Brush? mask;
property public float noiseFactor;
property public dev.chrisbanes.haze.HazeProgressive? progressive;
Expand All @@ -63,7 +63,7 @@ package dev.chrisbanes.haze {
method public boolean getBlurEnabled();
method public float getBlurRadius();
method public dev.chrisbanes.haze.HazeTint getFallbackTint();
method public float getInputScale();
method public dev.chrisbanes.haze.HazeInputScale getInputScale();
method public androidx.compose.ui.graphics.Brush? getMask();
method public float getNoiseFactor();
method public dev.chrisbanes.haze.HazeProgressive? getProgressive();
Expand All @@ -74,7 +74,7 @@ package dev.chrisbanes.haze {
method public void setBlurEnabled(boolean);
method public void setBlurRadius(float);
method public void setFallbackTint(dev.chrisbanes.haze.HazeTint);
method public void setInputScale(float);
method public void setInputScale(dev.chrisbanes.haze.HazeInputScale);
method public void setMask(androidx.compose.ui.graphics.Brush?);
method public void setNoiseFactor(float);
method public void setProgressive(dev.chrisbanes.haze.HazeProgressive?);
Expand All @@ -85,7 +85,7 @@ package dev.chrisbanes.haze {
property public abstract boolean blurEnabled;
property public abstract float blurRadius;
property public abstract dev.chrisbanes.haze.HazeTint fallbackTint;
property public abstract float inputScale;
property public abstract dev.chrisbanes.haze.HazeInputScale inputScale;
property public abstract androidx.compose.ui.graphics.Brush? mask;
property public abstract float noiseFactor;
property public abstract dev.chrisbanes.haze.HazeProgressive? progressive;
Expand All @@ -105,6 +105,27 @@ package dev.chrisbanes.haze {
field public static final float tintAlpha = 0.7f;
}

@dev.chrisbanes.haze.ExperimentalHazeApi public sealed interface HazeInputScale {
field public static final dev.chrisbanes.haze.HazeInputScale.Companion Companion;
}

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;
}

public static final class HazeInputScale.Fixed implements dev.chrisbanes.haze.HazeInputScale {
ctor public HazeInputScale.Fixed(float scale);
method public float component1();
method public dev.chrisbanes.haze.HazeInputScale.Fixed copy(float scale);
method public float getScale();
property public final float scale;
}

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

public final class HazeKt {
method @androidx.compose.runtime.Stable public static androidx.compose.ui.Modifier haze(androidx.compose.ui.Modifier, dev.chrisbanes.haze.HazeState state);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ private fun HazeChildNode.drawLinearGradientProgressiveEffectUsingLayers(

val tints = resolveTints()
val noiseFactor = resolveNoiseFactor()
val blurRadius = resolveBlurRadius().takeOrElse { 0.dp } * inputScale
val blurRadius = resolveBlurRadius().takeOrElse { 0.dp } * getInputScaleFactor()

for (i in seq) {
val fraction = i / steps.toFloat()
Expand Down
35 changes: 34 additions & 1 deletion haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChild.kt
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,40 @@ interface HazeChildScope {
* some point in the future.
*/
@ExperimentalHazeApi
var inputScale: Float
var inputScale: HazeInputScale
}

/**
* Value classes used for [HazeChildScope.inputScale].
*/
@ExperimentalHazeApi
sealed interface HazeInputScale {
/**
* No input scaling. This is functionally the same as `Fixed(1.0f)`
*/
data object None : HazeInputScale

/**
* An input scale which uses a fixed scale factor.
*
* @param scale The scale factor, in the range 0 < x <= 1.
*/
data class Fixed(val scale: Float) : HazeInputScale {
init {
require(scale > 0f && scale <= 1f) {
"scale needs to be in the range 0 < x <= 1f"
}
}
}

companion object {
/**
* The default [HazeInputScale] value. Currently this resolves to [HazeInputScale.None] but
* this may change in the future.
*/
@ExperimentalHazeApi
val Default: HazeInputScale get() = None
}
}

/**
Expand Down
17 changes: 11 additions & 6 deletions haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChildNode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,8 @@ class HazeChildNode(
}
}

override var inputScale: Float = 1f
override var inputScale: HazeInputScale = HazeInputScale.Default
set(value) {
require(inputScale > 0f && inputScale <= 1f) { "inputScale needs to be in the range 0 < x <= 1f" }
if (value != field) {
log(TAG) { "inputScale changed. Current: $field. New: $value" }
field = value
Expand Down Expand Up @@ -308,7 +307,8 @@ class HazeChildNode(
// The layer size is usually than the bounds. This is so that we include enough
// content around the edges to keep the blurring uniform. Without the extra border,
// the blur will naturally fade out at the edges.
val inflatedSize = layerSize * inputScale
val scaleFactor = getInputScaleFactor()
val inflatedSize = layerSize * scaleFactor
// This is the topLeft in the inflated bounds where the real are should be at [0,0]
val inflatedOffset = contentOffset

Expand All @@ -319,7 +319,7 @@ class HazeChildNode(
drawRect(bg)

clipRect {
scale(inputScale, Offset.Zero) {
scale(scaleFactor, Offset.Zero) {
translate(inflatedOffset - positionInContent) {
// Draw the content into our effect layer
drawLayer(contentLayer)
Expand All @@ -330,7 +330,7 @@ class HazeChildNode(

clipRect {
translate(-inflatedOffset) {
scale(1f / inputScale, Offset.Zero) {
scale(1f / scaleFactor, Offset.Zero) {
val p = progressive
if (p is HazeProgressive.LinearGradient) {
drawLinearGradientProgressiveEffect(
Expand Down Expand Up @@ -533,8 +533,13 @@ internal data class RenderEffectParams(
val inputScale: Float = 1f,
)

internal fun HazeChildNode.getInputScaleFactor(): Float = when (val s = inputScale) {
HazeInputScale.None -> 1f
is HazeInputScale.Fixed -> s.scale
}

internal fun HazeChildNode.getOrCreateRenderEffect(
inputScale: Float = this.inputScale,
inputScale: Float = getInputScaleFactor(),
blurRadius: Dp = resolveBlurRadius().takeOrElse { 0.dp } * inputScale,
noiseFactor: Float = resolveNoiseFactor(),
tints: List<HazeTint> = resolveTints(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@ import androidx.compose.ui.platform.testTag
import coil3.SingletonImageLoader
import coil3.compose.LocalPlatformContext
import coil3.request.ImageRequest
import dev.chrisbanes.haze.HazeInputScale

val Samples = listOf(
Sample("Scaffold") { ScaffoldSample(it) },
Sample("Scaffold (input scaled)") { ScaffoldSample(it, inputScale = 0.5f) },
Sample("Scaffold (input scaled)") { ScaffoldSample(it, inputScale = HazeInputScale.Fixed(0.5f)) },
Sample("Scaffold (progressive blur)") { ScaffoldSample(it, ScaffoldSampleMode.Progressive) },
Sample("Scaffold (progressive blur, input scaled)") {
ScaffoldSample(it, ScaffoldSampleMode.Progressive, 0.5f)
ScaffoldSample(it, ScaffoldSampleMode.Progressive, HazeInputScale.Fixed(0.5f))
},
Sample("Scaffold (masked)") { ScaffoldSample(it, ScaffoldSampleMode.Mask) },
Sample("Credit Card") { CreditCardSample(it) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import dev.chrisbanes.haze.HazeInputScale
import dev.chrisbanes.haze.HazeProgressive
import dev.chrisbanes.haze.HazeState
import dev.chrisbanes.haze.haze
Expand All @@ -57,7 +58,7 @@ enum class ScaffoldSampleMode {
fun ScaffoldSample(
navigator: Navigator,
mode: ScaffoldSampleMode = ScaffoldSampleMode.Default,
inputScale: Float = 1f,
inputScale: HazeInputScale = HazeInputScale.Default,
) {
val hazeState = remember { HazeState() }
val gridState = rememberLazyGridState()
Expand Down

0 comments on commit 334b6c2

Please sign in to comment.