Add support for mask mode none (#1440)

Fixes #1427
diff --git a/LottieSample/src/main/assets/Tests/MaskNone.json b/LottieSample/src/main/assets/Tests/MaskNone.json
new file mode 100644
index 0000000..69a3fa0
--- /dev/null
+++ b/LottieSample/src/main/assets/Tests/MaskNone.json
@@ -0,0 +1 @@
+{"v":"5.5.8","fr":29.9700012207031,"ip":0,"op":208.000008472014,"w":400,"h":400,"nm":"None","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"n","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-24,-26],[-24,239.516],[241.516,239.516],[241.516,-26]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[265.516,265.516],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12.758,18.758],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":208.000008472014,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/content/Mask.java b/lottie/src/main/java/com/airbnb/lottie/model/content/Mask.java
index 2dfc9f5..f709485 100644
--- a/lottie/src/main/java/com/airbnb/lottie/model/content/Mask.java
+++ b/lottie/src/main/java/com/airbnb/lottie/model/content/Mask.java
@@ -7,7 +7,8 @@
   public enum MaskMode {
     MASK_MODE_ADD,
     MASK_MODE_SUBTRACT,
-    MASK_MODE_INTERSECT
+    MASK_MODE_INTERSECT,
+    MASK_MODE_NONE
   }
 
   private final MaskMode maskMode;
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 b820304..20861f3 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
@@ -310,6 +310,9 @@
       path.transform(matrix);
 
       switch (mask.getMaskMode()) {
+        case MASK_MODE_NONE:
+          // Mask mode none will just render the original content so it is the whole bounds.
+          return;
         case MASK_MODE_SUBTRACT:
           // If there is a subtract mask, the mask could potentially be the size of the entire
           // canvas so we can't use the mask bounds.
@@ -378,6 +381,16 @@
       BaseKeyframeAnimation<ShapeData, Path> maskAnimation = this.mask.getMaskAnimations().get(i);
       BaseKeyframeAnimation<Integer, Integer> opacityAnimation = this.mask.getOpacityAnimations().get(i);
       switch (mask.getMaskMode()) {
+        case MASK_MODE_NONE:
+          // None mask should have no effect. If all masks are NONE, fill the
+          // mask canvas with a rectangle so it fully covers the original layer content.
+          // However, if there are other masks, they should be the only ones that have an effect so
+          // this should noop.
+          if (areAllMasksNone()) {
+            contentPaint.setAlpha(255);
+            canvas.drawRect(rect, contentPaint);
+          }
+          break;
         case MASK_MODE_ADD:
           if (mask.isInverted()) {
             applyInvertedAddMask(canvas, matrix, mask, maskAnimation, opacityAnimation);
@@ -411,6 +424,19 @@
     L.endSection("Layer#restoreLayer");
   }
 
+  private boolean areAllMasksNone() {
+    if (mask.getMaskAnimations().isEmpty()) {
+      return false;
+    }
+    boolean areAllMasksNone = true;
+    for (int i = 0; i < mask.getMasks().size(); i++) {
+      if (mask.getMasks().get(i).getMaskMode() != Mask.MaskMode.MASK_MODE_NONE) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   private void applyAddMask(Canvas canvas, Matrix matrix, Mask mask,
       BaseKeyframeAnimation<ShapeData, Path> maskAnimation, BaseKeyframeAnimation<Integer, Integer> opacityAnimation) {
     Path maskPath = maskAnimation.getValue();
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/MaskParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/MaskParser.java
index 97c75e5..d335fea 100644
--- a/lottie/src/main/java/com/airbnb/lottie/parser/MaskParser.java
+++ b/lottie/src/main/java/com/airbnb/lottie/parser/MaskParser.java
@@ -32,6 +32,9 @@
             case "s":
               maskMode = Mask.MaskMode.MASK_MODE_SUBTRACT;
               break;
+            case "n":
+              maskMode = Mask.MaskMode.MASK_MODE_NONE;
+              break;
             case "i":
               composition.addWarning(
                   "Animation contains intersect masks. They are not supported but will be treated like add masks.");