Skip to content

Commit

Permalink
Add blurEnabled on HazeChildScope property (#408)
Browse files Browse the repository at this point in the history
This allows developers on platforms where it is technically possible to
blur, but Haze defaults not to due to known issues.

Fixes #77
  • Loading branch information
chrisbanes authored Nov 13, 2024
1 parent 28b67eb commit 6a793fc
Show file tree
Hide file tree
Showing 23 changed files with 99 additions and 10 deletions.
7 changes: 7 additions & 0 deletions haze/api/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package dev.chrisbanes.haze {
method public float getAlpha();
method public long getBackgroundColor();
method public kotlin.jvm.functions.Function1<dev.chrisbanes.haze.HazeChildScope,kotlin.Unit>? getBlock();
method public boolean getBlurEnabled();
method public float getBlurRadius();
method public dev.chrisbanes.haze.HazeTint getFallbackTint();
method public androidx.compose.ui.graphics.Brush? getMask();
Expand All @@ -28,6 +29,7 @@ package dev.chrisbanes.haze {
method public void setAlpha(float);
method public void setBackgroundColor(long);
method public void setBlock(kotlin.jvm.functions.Function1<? super dev.chrisbanes.haze.HazeChildScope,kotlin.Unit>?);
method public void setBlurEnabled(boolean);
method public void setBlurRadius(float);
method public void setFallbackTint(dev.chrisbanes.haze.HazeTint);
method public void setMask(androidx.compose.ui.graphics.Brush?);
Expand All @@ -39,6 +41,7 @@ package dev.chrisbanes.haze {
property public float alpha;
property public long backgroundColor;
property public final kotlin.jvm.functions.Function1<dev.chrisbanes.haze.HazeChildScope,kotlin.Unit>? block;
property public boolean blurEnabled;
property public float blurRadius;
property public dev.chrisbanes.haze.HazeTint fallbackTint;
property public androidx.compose.ui.graphics.Brush? mask;
Expand All @@ -54,6 +57,7 @@ package dev.chrisbanes.haze {
public interface HazeChildScope {
method public float getAlpha();
method public long getBackgroundColor();
method public boolean getBlurEnabled();
method public float getBlurRadius();
method public dev.chrisbanes.haze.HazeTint getFallbackTint();
method public androidx.compose.ui.graphics.Brush? getMask();
Expand All @@ -63,6 +67,7 @@ package dev.chrisbanes.haze {
method public java.util.List<dev.chrisbanes.haze.HazeTint> getTints();
method public void setAlpha(float);
method public void setBackgroundColor(long);
method public void setBlurEnabled(boolean);
method public void setBlurRadius(float);
method public void setFallbackTint(dev.chrisbanes.haze.HazeTint);
method public void setMask(androidx.compose.ui.graphics.Brush?);
Expand All @@ -72,6 +77,7 @@ package dev.chrisbanes.haze {
method public void setTints(java.util.List<dev.chrisbanes.haze.HazeTint>);
property public abstract float alpha;
property public abstract long backgroundColor;
property public abstract boolean blurEnabled;
property public abstract float blurRadius;
property public abstract dev.chrisbanes.haze.HazeTint fallbackTint;
property public abstract androidx.compose.ui.graphics.Brush? mask;
Expand All @@ -82,6 +88,7 @@ package dev.chrisbanes.haze {
}

public final class HazeDefaults {
method public boolean blurEnabled();
method public float getBlurRadius();
method public dev.chrisbanes.haze.HazeStyle style(long backgroundColor, optional dev.chrisbanes.haze.HazeTint tint, optional float blurRadius, optional float noiseFactor);
method @Deprecated public dev.chrisbanes.haze.HazeStyle style(optional long backgroundColor, long tint, optional float blurRadius, optional float noiseFactor);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2024, Christopher Banes and the Haze project contributors
// SPDX-License-Identifier: Apache-2.0

package dev.chrisbanes.haze

import android.os.Build

/**
* By default we only enable blurring on SDK Level 32 and above, at the moment. You can override
* this via [HazeChildScope.blurEnabled] if required.
*
* See https://github.com/chrisbanes/haze/issues/77 for more details.
*/
internal actual fun isBlurEnabledByDefault(): Boolean = Build.VERSION.SDK_INT >= 32
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,11 @@ internal actual fun CompositionLocalConsumerModifierNode.createRenderEffect(para
.asComposeRenderEffect()
}

internal actual fun DrawScope.useGraphicLayers(): Boolean {
return Build.VERSION.SDK_INT >= 32 && drawContext.canvas.nativeCanvas.isHardwareAccelerated
/**
* This is the technical minimum for blurring to work on Android.
*/
internal actual fun DrawScope.canUseGraphicLayers(): Boolean {
return Build.VERSION.SDK_INT >= 31 && drawContext.canvas.nativeCanvas.isHardwareAccelerated
}

private val noiseTextureCache by lazy {
Expand Down
12 changes: 12 additions & 0 deletions haze/src/commonMain/kotlin/dev/chrisbanes/haze/Haze.kt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ object HazeDefaults {
blurRadius: Dp = this.blurRadius,
noiseFactor: Float = this.noiseFactor,
): HazeStyle = HazeStyle(backgroundColor, tint, blurRadius, noiseFactor)

/**
* Default values for [HazeChildScope.blurEnabled]. This function only returns `true` on
* platforms where we know blurring works reliably.
*
* This is not the same as everywhere where it technically works. The key omission here
* is Android SDK Level 31, which is known to have some issues with
* RenderNode invalidation.
*
* The devices excluded by this function may change in the future.
*/
fun blurEnabled(): Boolean = isBlurEnabledByDefault()
}

internal data class HazeNodeElement(
Expand Down
11 changes: 11 additions & 0 deletions haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChild.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.unit.Dp

interface HazeChildScope {

/**
* Whether the blur effect is enabled or not, when running on platforms which support blurring.
*
* When set to `false` a scrim effect will be used. When set to `true`, and running on a platform
* which does not support blurring, a scrim effect will be used.
*
* Defaults to [HazeDefaults.blurEnabled].
*/
var blurEnabled: Boolean

/**
* The opacity that the overall effect will drawn with, in the range of 0..1.
*/
Expand Down
17 changes: 12 additions & 5 deletions haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChildNode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ class HazeChildNode(
private var drawParametersDirty: Boolean = true
private var progressiveDirty: Boolean = true

override var blurEnabled: Boolean = HazeDefaults.blurEnabled()
set(value) {
if (value != field) {
log(TAG) { "blurEnabled changed. Current: $field. New: $value" }
field = value
drawParametersDirty = true
}
}

internal var compositionLocalStyle: HazeStyle = HazeStyle.Unspecified
set(value) {
if (field != value) {
Expand Down Expand Up @@ -251,11 +260,9 @@ class HazeChildNode(
return
}

if (useGraphicLayers()) {
val contentLayer = state.contentLayer
if (contentLayer != null) {
drawEffectWithGraphicsLayer(contentLayer)
}
val contentLayer = state.contentLayer
if (contentLayer != null && blurEnabled && canUseGraphicLayers()) {
drawEffectWithGraphicsLayer(contentLayer)
} else {
drawEffectWithScrim()
}
Expand Down
6 changes: 4 additions & 2 deletions haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeNode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class HazeNode(
state.contentDrawing = true
log(TAG) { "start draw()" }

if (useGraphicLayers()) {
if (canUseGraphicLayers()) {
val graphicsContext = currentValueOf(LocalGraphicsContext)

val contentLayer = state.contentLayer
Expand Down Expand Up @@ -91,7 +91,9 @@ class HazeNode(
}
}

internal expect fun DrawScope.useGraphicLayers(): Boolean
internal expect fun isBlurEnabledByDefault(): Boolean

internal expect fun DrawScope.canUseGraphicLayers(): Boolean

internal fun HazeTint.boostForFallback(blurRadius: Dp): HazeTint {
// For color, we can boost the alpha
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@ class HazeScreenshotTest : ScreenshotTest() {
captureRoot()
}

@Test
fun creditCard_blurEnabled() = runScreenshotTest {
var blurEnabled by mutableStateOf(HazeDefaults.blurEnabled())

setContent {
ScreenshotTheme {
CreditCardSample(tint = DefaultTint, blurEnabled = blurEnabled)
}
}

waitForIdle()
captureRoot("default")

blurEnabled = false
waitForIdle()
captureRoot("disabled")

blurEnabled = true
waitForIdle()
captureRoot("enabled")
}

@Test
fun creditCard_style() = runScreenshotTest {
setContent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ internal fun CreditCardSample(
blurRadius: Dp = 8.dp,
shape: RoundedCornerShape = RoundedCornerShape(16.dp),
enabled: Boolean = true,
blurEnabled: Boolean = HazeDefaults.blurEnabled(),
mask: Brush? = null,
progressive: HazeProgressive? = null,
alpha: Float = 1f,
Expand Down Expand Up @@ -71,6 +72,7 @@ internal fun CreditCardSample(
when {
enabled -> {
Modifier.hazeChild(state = hazeState) {
this.blurEnabled = blurEnabled
this.style = style
backgroundColor = surfaceColor
noiseFactor = HazeDefaults.noiseFactor
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2024, Christopher Banes and the Haze project contributors
// SPDX-License-Identifier: Apache-2.0

package dev.chrisbanes.haze

/**
* Skiko always has blurring support (that we know of).
*/
internal actual fun isBlurEnabledByDefault(): Boolean = true
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.jetbrains.skia.ImageFilter
import org.jetbrains.skia.RuntimeShaderBuilder
import org.jetbrains.skia.Shader

internal actual fun DrawScope.useGraphicLayers(): Boolean = true
internal actual fun DrawScope.canUseGraphicLayers(): Boolean = true

internal actual fun CompositionLocalConsumerModifierNode.createRenderEffect(params: RenderEffectParams): RenderEffect? {
require(params.blurRadiusPx >= 0f) { "blurRadius needs to be equal or greater than 0f" }
Expand Down

0 comments on commit 6a793fc

Please sign in to comment.