Skip to content

Commit

Permalink
Enable mix-blend-mode on ReactRootView so blending works with app bac…
Browse files Browse the repository at this point in the history
…kground (#47336)

Summary:
Pull Request resolved: #47336

Before mix-blend-mode would not blend with the background color due to it not being a ViewGroup. This adds the mix-blend-mode logic to ReactRootView so blending works

Changelog:
[Android][Fixed] - Enable mix-blend-mode on ReactRootView so blending works with app background

Reviewed By: NickGerleman

Differential Revision: D65156543

fbshipit-source-id: b3628b667573d0b56c74214e40d21c656fda495a
  • Loading branch information
jorge-cab authored and facebook-github-bot committed Nov 24, 2024
1 parent 30e75a5 commit 24b0ded
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 13 deletions.
1 change: 1 addition & 0 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ public class com/facebook/react/ReactRootView : android/widget/FrameLayout, com/
protected fun dispatchJSPointerEvent (Landroid/view/MotionEvent;Z)V
protected fun dispatchJSTouchEvent (Landroid/view/MotionEvent;)V
public fun dispatchKeyEvent (Landroid/view/KeyEvent;)Z
protected fun drawChild (Landroid/graphics/Canvas;Landroid/view/View;J)Z
protected fun finalize ()V
public fun getAppProperties ()Landroid/os/Bundle;
public fun getCurrentReactContext ()Lcom/facebook/react/bridge/ReactContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@
package com.facebook.react;

import static com.facebook.infer.annotation.ThreadConfined.UI;
import static com.facebook.react.uimanager.BlendModeHelper.needsIsolatedLayer;
import static com.facebook.react.uimanager.common.UIManagerType.DEFAULT;
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;

import android.content.Context;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
Expand Down Expand Up @@ -65,6 +68,7 @@
import com.facebook.react.uimanager.RootViewUtil;
import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.uimanager.common.UIManagerType;
import com.facebook.react.uimanager.common.ViewUtil;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.systrace.Systrace;
import java.util.concurrent.atomic.AtomicInteger;
Expand Down Expand Up @@ -290,6 +294,30 @@ protected void dispatchDraw(Canvas canvas) {
}
}

@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {

BlendMode mixBlendMode = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& ViewUtil.getUIManagerType(this) == UIManagerType.FABRIC
&& needsIsolatedLayer(this)) {
mixBlendMode = (BlendMode) child.getTag(R.id.mix_blend_mode);
if (mixBlendMode != null) {
Paint p = new Paint();
p.setBlendMode(mixBlendMode);
canvas.saveLayer(0, 0, getWidth(), getHeight(), p);
}
}

boolean result = super.drawChild(canvas, child, drawingTime);

if (mixBlendMode != null) {
canvas.restore();
}

return result;
}

@Override
public boolean dispatchKeyEvent(KeyEvent ev) {
if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ package com.facebook.react.uimanager
import android.annotation.TargetApi
import android.graphics.BlendMode
import android.os.Build
import android.view.ViewGroup
import androidx.core.view.children
import com.facebook.react.R

@TargetApi(29)
internal object BlendModeHelper {
Expand Down Expand Up @@ -41,4 +44,8 @@ internal object BlendModeHelper {
else -> throw IllegalArgumentException("Invalid mix-blend-mode name: $mixBlendMode")
}
}

@JvmStatic
public fun needsIsolatedLayer(view: ViewGroup): Boolean =
view.children.any { it.getTag(R.id.mix_blend_mode) != null }
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import com.facebook.react.touch.ReactHitSlopView;
import com.facebook.react.touch.ReactInterceptingViewGroup;
import com.facebook.react.uimanager.BackgroundStyleApplicator;
import com.facebook.react.uimanager.BlendModeHelper;
import com.facebook.react.uimanager.LengthPercentage;
import com.facebook.react.uimanager.LengthPercentageType;
import com.facebook.react.uimanager.MeasureSpecAssertions;
Expand Down Expand Up @@ -747,16 +748,6 @@ private void removeFromArray(int index) {
}
}

private boolean needsIsolatedLayer() {
for (int i = 0; i < getChildCount(); i++) {
if (getChildAt(i).getTag(R.id.mix_blend_mode) != null) {
return true;
}
}

return false;
}

@Override
public @Nullable Rect getHitSlopRect() {
return mHitSlopRect;
Expand Down Expand Up @@ -793,7 +784,7 @@ public void setOverflow(@Nullable String overflow) {

@Override
public void setOverflowInset(int left, int top, int right, int bottom) {
if (needsIsolatedLayer()
if (BlendModeHelper.needsIsolatedLayer(this)
&& (mOverflowInset.left != left
|| mOverflowInset.top != top
|| mOverflowInset.right != right
Expand Down Expand Up @@ -823,7 +814,7 @@ public Rect getOverflowInset() {
public void draw(Canvas canvas) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& ViewUtil.getUIManagerType(this) == UIManagerType.FABRIC
&& needsIsolatedLayer()) {
&& BlendModeHelper.needsIsolatedLayer(this)) {

// Check if the view is a stacking context and has children, if it does, do the rendering
// offscreen and then composite back. This follows the idea of group isolation on blending
Expand Down Expand Up @@ -859,7 +850,8 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
}

BlendMode mixBlendMode = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && needsIsolatedLayer()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& BlendModeHelper.needsIsolatedLayer(this)) {
mixBlendMode = (BlendMode) child.getTag(R.id.mix_blend_mode);
if (mixBlendMode != null) {
Paint p = new Paint();
Expand Down

0 comments on commit 24b0ded

Please sign in to comment.