Added the ability to outline masks and mattes (#1658)
diff --git a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt b/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt
index 30271c3..6db0e7a 100644
--- a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt
+++ b/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt
@@ -108,6 +108,7 @@
snapshotProdAnimations()
testNightMode()
testApplyOpacityToLayer()
+ testOutlineMasksAndMattes()
snapshotter.finalizeReportAndUpload()
}
}
@@ -983,6 +984,16 @@
}
}
+ private suspend fun testOutlineMasksAndMattes() {
+ withFilmStripView(
+ "Tests/Masks.json",
+ "Outline Masks and Mattes",
+ "Enabled"
+ ) { filmStripView ->
+ filmStripView.setOutlineMasksAndMattes(true)
+ }
+ }
+
private suspend fun withDrawable(assetName: String, snapshotName: String, snapshotVariant: String, callback: (LottieDrawable) -> Unit) {
val result = LottieCompositionFactory.fromAssetSync(application, assetName)
val composition = result.value
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerFragment.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerFragment.kt
index 0f92052..944382d 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerFragment.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerFragment.kt
@@ -179,6 +179,12 @@
binding.controlBarPlayerControls.lottieVersionView.animateVisible(!it)
}
+ binding.controlBar.masksAndMattesToggle.setOnClickListener { viewModel.toggleOutlineMasksAndMattes() }
+ viewModel.selectSubscribe(PlayerState::outlineMasksAndMattes) {
+ binding.controlBar.masksAndMattesToggle.isActivated = it
+ binding.animationView.setOutlineMasksAndMattes(it)
+ }
+
binding.controlBar.backgroundColorToggle.setOnClickListener { viewModel.toggleBackgroundColorVisible() }
binding.controlBarBackgroundColor.closeBackgroundColorButton.setOnClickListener { viewModel.setBackgroundColorVisible(false) }
viewModel.selectSubscribe(PlayerState::backgroundColorVisible) {
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt
index a6bce9f..a9ef3ed 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/PlayerViewModel.kt
@@ -18,6 +18,7 @@
val controlsVisible: Boolean = true,
val controlBarVisible: Boolean = true,
val renderGraphVisible: Boolean = false,
+ val outlineMasksAndMattes: Boolean = false,
val borderVisible: Boolean = false,
val backgroundColorVisible: Boolean = false,
val scaleVisible: Boolean = false,
@@ -64,6 +65,8 @@
fun toggleRenderGraphVisible() = setState { copy(renderGraphVisible = !renderGraphVisible) }
+ fun toggleOutlineMasksAndMattes() = setState { copy(outlineMasksAndMattes = !outlineMasksAndMattes) }
+
fun toggleBorderVisible() = setState { copy(borderVisible = !borderVisible) }
fun toggleBackgroundColorVisible() = setState { copy(backgroundColorVisible = !backgroundColorVisible) }
diff --git a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/FilmStripView.kt b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/FilmStripView.kt
index 99bb21a..d93961b 100644
--- a/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/FilmStripView.kt
+++ b/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/views/FilmStripView.kt
@@ -40,4 +40,8 @@
fun setApplyingOpacityToLayersEnabled(isApplyingOpacityToLayersEnabled: Boolean) {
animationViews.forEach { it.setApplyingOpacityToLayersEnabled(isApplyingOpacityToLayersEnabled) }
}
+
+ fun setOutlineMasksAndMattes(outline: Boolean) {
+ animationViews.forEach { it.setOutlineMasksAndMattes(outline) }
+ }
}
diff --git a/LottieSample/src/main/res/drawable/ic_show_masks_and_mattes.xml b/LottieSample/src/main/res/drawable/ic_show_masks_and_mattes.xml
new file mode 100644
index 0000000..c997121
--- /dev/null
+++ b/LottieSample/src/main/res/drawable/ic_show_masks_and_mattes.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M3,5h2L5,3c-1.1,0 -2,0.9 -2,2zM3,13h2v-2L3,11v2zM7,21h2v-2L7,19v2zM3,9h2L5,7L3,7v2zM13,3h-2v2h2L13,3zM19,3v2h2c0,-1.1 -0.9,-2 -2,-2zM5,21v-2L3,19c0,1.1 0.9,2 2,2zM3,17h2v-2L3,15v2zM9,3L7,3v2h2L9,3zM11,21h2v-2h-2v2zM19,13h2v-2h-2v2zM19,21c1.1,0 2,-0.9 2,-2h-2v2zM19,9h2L21,7h-2v2zM19,17h2v-2h-2v2zM15,21h2v-2h-2v2zM15,5h2L17,3h-2v2zM7,17h10L17,7L7,7v10zM9,9h6v6L9,15L9,9z"/>
+</vector>
diff --git a/LottieSample/src/main/res/layout/control_bar.xml b/LottieSample/src/main/res/layout/control_bar.xml
index 3c1ad37..b44548c 100644
--- a/LottieSample/src/main/res/layout/control_bar.xml
+++ b/LottieSample/src/main/res/layout/control_bar.xml
@@ -21,6 +21,11 @@
app:src="@drawable/ic_chart"
app:text="@string/control_bar_render_graph" />
<com.airbnb.lottie.samples.views.ControlBarItemToggleView
+ android:id="@+id/masksAndMattesToggle"
+ style="@style/ControlBarItem"
+ app:src="@drawable/ic_show_masks_and_mattes"
+ app:text="@string/control_bar_masks_and_mattes" />
+ <com.airbnb.lottie.samples.views.ControlBarItemToggleView
android:id="@+id/warningsButton"
style="@style/ControlBarItem" />
<com.airbnb.lottie.samples.views.ControlBarItemToggleView
diff --git a/LottieSample/src/main/res/values/strings.xml b/LottieSample/src/main/res/values/strings.xml
index da68ca1..ad9fc55 100644
--- a/LottieSample/src/main/res/values/strings.xml
+++ b/LottieSample/src/main/res/values/strings.xml
@@ -46,6 +46,7 @@
<string name="control_bar_hardware_acceleration">Hardware Acceleration</string>
<string name="control_bar_render_graph">Render Graph</string>
<string name="control_bar_scale">Scale</string>
+ <string name="control_bar_masks_and_mattes">Outline Masks</string>
<string name="control_bar_trim">Trim</string>
<string name="control_bar_speed">Speed</string>
<string name="control_bar_key_paths">Show KeyPaths</string>
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java
index 5bf4b31..70f0a9a 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java
@@ -370,6 +370,16 @@
}
/**
+ * Enable this to debug slow animations by outlining masks and mattes. The performance overhead of the masks and mattes will
+ * be proportional to the surface area of all of the masks/mattes combined.
+ *
+ * DO NOT leave this enabled in production.
+ */
+ public void setOutlineMasksAndMattes(boolean outline) {
+ lottieDrawable.setOutlineMasksAndMattes(outline);
+ }
+
+ /**
* Sets the animation from a file in the raw directory.
* This will load and deserialize the file asynchronously.
*/
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
index 34faf26..e171b4b 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
@@ -94,6 +94,7 @@
private CompositionLayer compositionLayer;
private int alpha = 255;
private boolean performanceTrackingEnabled;
+ private boolean outlineMasksAndMattes;
private boolean isApplyingOpacityToLayersEnabled;
private boolean isExtraScaleEnabled = true;
/**
@@ -249,6 +250,19 @@
}
}
+ /**
+ * Enable this to debug slow animations by outlining masks and mattes. The performance overhead of the masks and mattes will
+ * be proportional to the surface area of all of the masks/mattes combined.
+ *
+ * DO NOT leave this enabled in production.
+ */
+ void setOutlineMasksAndMattes(boolean outline) {
+ outlineMasksAndMattes = outline;
+ if (compositionLayer != null) {
+ compositionLayer.setOutlineMasksAndMattes(outline);
+ }
+ }
+
@Nullable
public PerformanceTracker getPerformanceTracker() {
if (composition != null) {
@@ -296,6 +310,9 @@
private void buildCompositionLayer() {
compositionLayer = new CompositionLayer(
this, LayerParser.parse(composition), composition.getLayers(), composition);
+ if (outlineMasksAndMattes) {
+ compositionLayer.setOutlineMasksAndMattes(true);
+ }
}
public void clearComposition() {
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/layer/BaseLayer.java b/lottie/src/main/java/com/airbnb/lottie/model/layer/BaseLayer.java
index df33cf6..9f12706 100644
--- a/lottie/src/main/java/com/airbnb/lottie/model/layer/BaseLayer.java
+++ b/lottie/src/main/java/com/airbnb/lottie/model/layer/BaseLayer.java
@@ -97,6 +97,9 @@
final TransformKeyframeAnimation transform;
private boolean visible = true;
+ private boolean outlineMasksAndMattes;
+ @Nullable private Paint outlineMasksAndMattesPaint;
+
BaseLayer(LottieDrawable lottieDrawable, Layer layerModel) {
this.lottieDrawable = lottieDrawable;
this.layerModel = layerModel;
@@ -125,6 +128,19 @@
setupInOutAnimations();
}
+ /**
+ * Enable this to debug slow animations by outlining masks and mattes. The performance overhead of the masks and mattes will
+ * be proportional to the surface area of all of the masks/mattes combined.
+ *
+ * DO NOT leave this enabled in production.
+ */
+ void setOutlineMasksAndMattes(boolean outline) {
+ if (outline && outlineMasksAndMattesPaint == null) {
+ outlineMasksAndMattesPaint = new LPaint();
+ }
+ outlineMasksAndMattes = outline;
+ }
+
@Override
public void onValueChanged() {
invalidateSelf();
@@ -229,13 +245,6 @@
L.beginSection("Layer#computeBounds");
getBounds(rect, matrix, false);
- // Uncomment this to draw matte outlines.
- /* Paint paint = new LPaint();
- paint.setColor(Color.RED);
- paint.setStyle(Paint.Style.STROKE);
- paint.setStrokeWidth(3);
- canvas.drawRect(rect, paint); */
-
intersectBoundsWithMatte(rect, parentMatrix);
matrix.preConcat(transform.getMatrix());
@@ -282,6 +291,16 @@
L.endSection("Layer#restoreLayer");
}
+ if (outlineMasksAndMattes && outlineMasksAndMattesPaint != null) {
+ outlineMasksAndMattesPaint.setStyle(Paint.Style.STROKE);
+ outlineMasksAndMattesPaint.setColor(0xFFFC2803);
+ outlineMasksAndMattesPaint.setStrokeWidth(4);
+ canvas.drawRect(rect, outlineMasksAndMattesPaint);
+ outlineMasksAndMattesPaint.setStyle(Paint.Style.FILL);
+ outlineMasksAndMattesPaint.setColor(0x50EBEBEB);
+ canvas.drawRect(rect, outlineMasksAndMattesPaint);
+ }
+
recordRenderTime(L.endSection(drawTraceName));
}
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/layer/CompositionLayer.java b/lottie/src/main/java/com/airbnb/lottie/model/layer/CompositionLayer.java
index a98d0cb..33361ed 100644
--- a/lottie/src/main/java/com/airbnb/lottie/model/layer/CompositionLayer.java
+++ b/lottie/src/main/java/com/airbnb/lottie/model/layer/CompositionLayer.java
@@ -88,6 +88,13 @@
}
}
+ @Override public void setOutlineMasksAndMattes(boolean outline) {
+ super.setOutlineMasksAndMattes(outline);
+ for (BaseLayer layer : layers) {
+ layer.setOutlineMasksAndMattes(outline);
+ }
+ }
+
@Override void drawLayer(Canvas canvas, Matrix parentMatrix, int parentAlpha) {
L.beginSection("CompositionLayer#draw");
newClipRect.set(0, 0, layerModel.getPreCompWidth(), layerModel.getPreCompHeight());