Apply blend modes on layer level and add Multiply blend mode (#2519)

This commit improves blend mode support in lottie-android in two ways:
* Applying blend modes on layer-level, instead of fill level
* Adding support for the Multiply blend mode

## Applying blend modes on layer level

The Lottie format defines blend modes as attributes on a layer. However, lottie-android is presently applying the layer blend modes on a solid color fill only. Notably, this causes any stroked or gradient-filled shapes or image layers to blend incorrectly, such as in this file:

[stroke-blending-test.json](https://github.com/user-attachments/files/16346206/stroke-blending-test.json)

(The file contains a filled + stroked shape that renders as a pink square on other platforms, but renders with a visible stroke on lottie-android since its blend mode is applied only on the fill.)

Instead, we move this decision to `BaseLayer` by analogy to transparent layer handling, which is closer to how the format specifies the property and fixes these cases.

## Multiply support

`BlendModeCompat` is designed to resolve to either a `BlendMode` (added in Android Q, supporting most modern blend modes) or `PorterDuff.Mode` (always available, but a smaller choice of modes as it is mostly focused on alpha compositing).

We use `BlendModeCompat` to support Lottie layer blend modes (`bm` key) to ensure compatibility on all platforms. For consistency, we don't  support values which don't have a `PorterDuff.Mode` equivalent.

Our support for Lottie blend modes did not include Multiply due to a slightly different behavior between the `PorterDuff.MULTIPLY` (exposed as `BlendModeCompat.MODULATE`) and `BlendModeCompat.MULTIPLY` variants. Namely, the formula used for `PorterDuff.MODULATE`, combined with alpha-premultiplication done by Skia, means that a layer with an alpha < 1.0 and multiply blend mode will also darken the destination:

![Incorrect-Blend](https://github.com/user-attachments/assets/6a2113ef-4bac-4bbc-830b-1353adf4ee2b)

(Multiply-blended layers with < 1.0 alpha on the left, Screen-blended layers with < 1.0 alpha on the right)

However, what we can do instead is clear the canvas with a solid white color instead of transparent before drawing the layer's contents as normal. When blending the resulting bitmap over an opaque background using `PorterDuff.MULTIPLY` (i.e. `BlendModeCompat.MODULATE`), the end result will be as if we had used `BlendModeCompat.MULTIPLY`, since all-1.0 (white) is a multiplication identity:

![Correct-Blend](https://github.com/user-attachments/assets/126022ef-6e47-48ee-b803-1d9800ca2c75)

This PR implements the latter solution and adds a consistent support for the Multiply blend mode for all Android versions.

*Test file used:*  [blendmode-tests-multiply+screen+bg.zip](https://github.com/user-attachments/files/16365843/blendmode-tests-multiply%2Bscreen%2Bbg.zip)
3 files changed
tree: ca2525f675add7b5bd1367156a513a8c126c44ec
  1. .github/
  2. .idea/
  3. After Effects Samples/
  4. app-benchmark/
  5. baselineprofile/
  6. benchmark/
  7. gifs/
  8. gradle/
  9. images/
  10. issue-repro/
  11. issue-repro-compose/
  12. lottie/
  13. lottie-compose/
  14. sample/
  15. sample-compose/
  16. snapshot-tests/
  17. .editorconfig
  18. .gitattributes
  19. .gitignore
  20. build.gradle
  21. CHANGELOG.md
  22. CHANGELOG_COMPOSE.md
  23. CODE_OF_CONDUCT.md
  24. deploy_snapshot.sh
  25. DESIGNER_NOTES.md
  26. gradle.properties
  27. gradlew
  28. gradlew.bat
  29. LICENSE
  30. lint.xml
  31. post_pr_comment.js
  32. README.md
  33. RELEASE.md
  34. settings.gradle
  35. sign.sh
  36. update-baseline-profiles.sh
  37. upload_release.sh
  38. version.sh
  39. versions.properties
README.md

Lottie for Android, iOS, React Native, Web, and Windows

Build Status

Lottie is a mobile library for Android and iOS that parses Adobe After Effects animations exported as json with Bodymovin and renders them natively on mobile!

For the first time, designers can create and ship beautiful animations without an engineer painstakingly recreating it by hand. They say a picture is worth 1,000 words so here are 13,000:

Sponsors

Lottie is maintained and improved on nights and weekends. If you use Lottie in your app, please consider sponsoring it to help ensure that we can continue to improve the project we love. Click the sponsor button above to learn more

Lead Sponsors

View documentation, FAQ, help, examples, and more at airbnb.io/lottie

Example1

Example2

Example3

Community

Example4

Download

Gradle is the only supported build configuration, so just add the dependency to your project build.gradle file:

dependencies {
  implementation 'com.airbnb.android:lottie:$lottieVersion'
}

The latest Lottie version is: lottieVersion

The latest stable Lottie-Compose version is: lottieVersion Click here for more information on Lottie-Compose.

Lottie 2.8.0 and above only supports projects that have been migrated to androidx. For more information, read Google's migration guide.

Contributing

Because development has started for Lottie Compose, Gradle, and the Android Gradle Plugin will be kept up to date with the latest canaries. This also requires you to use Android Studio Canary builds. Preview builds can be installed side by side with stable versions.