Reimplemented masks and mattes (#1135)

This should greatly improve the compatibility of multiple add and subtract masks and adds support for inverted masks and intersect masks.
diff --git a/After Effects Samples/Masks.aep b/After Effects Samples/Masks.aep
new file mode 100644
index 0000000..08d8e7c
--- /dev/null
+++ b/After Effects Samples/Masks.aep
Binary files differ
diff --git a/LottieSample/src/main/assets/Tests/MaskInv.json b/LottieSample/src/main/assets/Tests/MaskInv.json
index 9c30721..9b5786f 100644
--- a/LottieSample/src/main/assets/Tests/MaskInv.json
+++ b/LottieSample/src/main/assets/Tests/MaskInv.json
@@ -1 +1,222 @@
-{"v":"4.11.1","fr":29.9700012207031,"ip":0,"op":900.000036657751,"w":400,"h":400,"nm":"MaskInv","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":1,"nm":"Background","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,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":"a","pt":{"a":0,"k":{"i":[[50.031,0],[0,-50.031],[-50.031,0],[0,50.031]],"o":[[-50.031,0],[0,50.031],[50.031,0],[0,-50.031]],"v":[[150.59,88],[60,178.59],[150.59,269.18],[241.18,178.59]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 2"},{"inv":false,"mode":"s","pt":{"a":0,"k":{"i":[[55.912,0],[0,-55.912],[-55.912,0],[0,55.912]],"o":[[-55.912,0],[0,55.912],[55.912,0],[0,-55.912]],"v":[[221.238,126],[120,227.238],[221.238,328.477],[322.477,227.238]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"sw":400,"sh":400,"sc":"#ff0000","ip":0,"op":900.000036657751,"st":0,"bm":0}]}
\ No newline at end of file
+{
+  "v": "4.11.1",
+  "fr": 29.9700012207031,
+  "ip": 0,
+  "op": 900.000036657751,
+  "w": 400,
+  "h": 400,
+  "nm": "MaskInv",
+  "ddd": 0,
+  "assets": [],
+  "layers": [
+    {
+      "ddd": 0,
+      "ind": 1,
+      "ty": 1,
+      "nm": "Background",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 0,
+          "k": 100,
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            0,
+            0,
+            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": "a",
+          "pt": {
+            "a": 0,
+            "k": {
+              "i": [
+                [
+                  50.031,
+                  0
+                ],
+                [
+                  0,
+                  -50.031
+                ],
+                [
+                  -50.031,
+                  0
+                ],
+                [
+                  0,
+                  50.031
+                ]
+              ],
+              "o": [
+                [
+                  -50.031,
+                  0
+                ],
+                [
+                  0,
+                  50.031
+                ],
+                [
+                  50.031,
+                  0
+                ],
+                [
+                  0,
+                  -50.031
+                ]
+              ],
+              "v": [
+                [
+                  150.59,
+                  88
+                ],
+                [
+                  60,
+                  178.59
+                ],
+                [
+                  150.59,
+                  269.18
+                ],
+                [
+                  241.18,
+                  178.59
+                ]
+              ],
+              "c": true
+            },
+            "ix": 1
+          },
+          "o": {
+            "a": 0,
+            "k": 100,
+            "ix": 3
+          },
+          "x": {
+            "a": 0,
+            "k": 0,
+            "ix": 4
+          },
+          "nm": "Mask 2"
+        },
+        {
+          "inv": false,
+          "mode": "s",
+          "pt": {
+            "a": 0,
+            "k": {
+              "i": [
+                [
+                  55.912,
+                  0
+                ],
+                [
+                  0,
+                  -55.912
+                ],
+                [
+                  -55.912,
+                  0
+                ],
+                [
+                  0,
+                  55.912
+                ]
+              ],
+              "o": [
+                [
+                  -55.912,
+                  0
+                ],
+                [
+                  0,
+                  55.912
+                ],
+                [
+                  55.912,
+                  0
+                ],
+                [
+                  0,
+                  -55.912
+                ]
+              ],
+              "v": [
+                [
+                  221.238,
+                  126
+                ],
+                [
+                  120,
+                  227.238
+                ],
+                [
+                  221.238,
+                  328.477
+                ],
+                [
+                  322.477,
+                  227.238
+                ]
+              ],
+              "c": true
+            },
+            "ix": 1
+          },
+          "o": {
+            "a": 0,
+            "k": 100,
+            "ix": 3
+          },
+          "x": {
+            "a": 0,
+            "k": 0,
+            "ix": 4
+          },
+          "nm": "Mask 1"
+        }
+      ],
+      "sw": 400,
+      "sh": 400,
+      "sc": "#ff0000",
+      "ip": 0,
+      "op": 900.000036657751,
+      "st": 0,
+      "bm": 0
+    }
+  ]
+}
\ No newline at end of file
diff --git a/LottieSample/src/main/assets/Tests/Masks.json b/LottieSample/src/main/assets/Tests/Masks.json
new file mode 100644
index 0000000..c7daa76
--- /dev/null
+++ b/LottieSample/src/main/assets/Tests/Masks.json
@@ -0,0 +1 @@
+{"v":"5.3.4","fr":29.9700012207031,"ip":0,"op":61.0000024845809,"w":200,"h":300,"nm":"Mask","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[205.5,320.5,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":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-79,-78],[-79,-38],[-39,-38],[-39,-78]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 2"},{"inv":true,"mode":"s","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-113,-110.622],[-113,-56],[-61,-56.878],[-61,-111.5]],"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":[50,50],"ix":2},"p":{"a":0,"k":[-83,-72],"ix":3},"r":{"a":0,"k":0,"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,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.658,5.658],"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,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61.0000024845809,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[205.5,251.5,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":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-79,-78],[-79,-38],[-39,-38],[-39,-78]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 2"},{"inv":true,"mode":"s","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-113,-110.622],[-113,-56],[-61,-56.878],[-61,-111.5]],"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":[50,50],"ix":2},"p":{"a":0,"k":[-83,-72],"ix":3},"r":{"a":0,"k":0,"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,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.658,5.658],"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,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61.0000024845809,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[205.5,192.5,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":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-79,-78],[-79,-38],[-39,-38],[-39,-78]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 2"},{"inv":false,"mode":"s","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-113,-110.622],[-113,-56],[-61,-56.878],[-61,-111.5]],"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":[50,50],"ix":2},"p":{"a":0,"k":[-83,-72],"ix":3},"r":{"a":0,"k":0,"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,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.658,5.658],"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,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61.0000024845809,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[108.5,319.5,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":true,"mode":"s","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-113,-110.622],[-113,-56],[-61,-56.878],[-61,-111.5]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"},{"inv":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-79,-78],[-79,-38],[-39,-38],[-39,-78]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 2"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[-83,-72],"ix":3},"r":{"a":0,"k":0,"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,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.658,5.658],"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,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61.0000024845809,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[108.5,258.5,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":"s","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-113,-110.622],[-113,-56],[-61,-56.878],[-61,-111.5]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"},{"inv":true,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-79,-78],[-79,-38],[-39,-38],[-39,-78]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 2"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[-83,-72],"ix":3},"r":{"a":0,"k":0,"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,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.658,5.658],"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,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61.0000024845809,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[108.5,190.5,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":true,"mode":"s","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-113,-110.622],[-113,-56],[-61,-56.878],[-61,-111.5]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"},{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-79,-78],[-79,-38],[-39,-38],[-39,-78]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 2"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[-83,-72],"ix":3},"r":{"a":0,"k":0,"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,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.658,5.658],"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,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61.0000024845809,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[108.5,105.5,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":"s","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-113,-110.622],[-113,-56],[-61,-56.878],[-61,-111.5]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"},{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-78.75,-78],[-78.75,-38],[-38.75,-38],[-38.75,-78]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 2"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[-83,-72],"ix":3},"r":{"a":0,"k":0,"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,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.658,5.658],"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,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61.0000024845809,"st":0,"bm":0},{"ddd":0,"ind":8,"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":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[176.5,105.5,0],"e":[235,105.5,0],"to":[9.75,0,0],"ti":[-9.75,0,0]},{"t":60.0000024438501}],"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":"a","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-79,-78],[-79,-38],[-39,-38],[-39,-78]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 2"},{"inv":false,"mode":"s","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-113,-110.622],[-113,-56],[-61,-56.878],[-61,-111.5]],"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":[50,50],"ix":2},"p":{"a":0,"k":[-83,-72],"ix":3},"r":{"a":0,"k":0,"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,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15.658,5.658],"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,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61.0000024845809,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
index 846a7c4..3ef4f62 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
@@ -5,9 +5,13 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.Matrix;
+import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Typeface;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
@@ -288,6 +292,15 @@
     return PixelFormat.TRANSLUCENT;
   }
 
+  private void drawRect(Canvas canvas, float lp, float tp, float rp, float bp, @Nullable PorterDuff.Mode mode, int color) {
+    Paint paint = new Paint();
+    paint.setColor(color);
+    if (mode != null) {
+      paint.setXfermode(new PorterDuffXfermode(mode));
+    }
+    canvas.drawRect(canvas.getWidth() * lp, canvas.getHeight() * tp, canvas.getWidth() * rp, canvas.getHeight() * bp, paint);
+  }
+
   @Override
   public void draw(@NonNull Canvas canvas) {
     isDirty = false;
diff --git a/lottie/src/main/java/com/airbnb/lottie/animation/LPaint.java b/lottie/src/main/java/com/airbnb/lottie/animation/LPaint.java
index 0462a1d..93869aa 100644
--- a/lottie/src/main/java/com/airbnb/lottie/animation/LPaint.java
+++ b/lottie/src/main/java/com/airbnb/lottie/animation/LPaint.java
@@ -1,6 +1,8 @@
 package com.airbnb.lottie.animation;
 
 import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.os.LocaleList;
 
 import androidx.annotation.NonNull;
@@ -12,12 +14,23 @@
  */
 public class LPaint extends Paint {
     public LPaint() {
+        super();
     }
 
     public LPaint(int flags) {
         super(flags);
     }
 
+    public LPaint(PorterDuff.Mode porterDuffMode) {
+        super();
+        setXfermode(new PorterDuffXfermode(porterDuffMode));
+    }
+
+    public LPaint(int flags, PorterDuff.Mode porterDuffMode) {
+        super(flags);
+        setXfermode(new PorterDuffXfermode(porterDuffMode));
+    }
+
     @Override
     public void setTextLocales(@NonNull LocaleList locales) {
         // Do nothing.
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 92cc94f..2dfc9f5 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
@@ -13,11 +13,13 @@
   private final MaskMode maskMode;
   private final AnimatableShapeValue maskPath;
   private final AnimatableIntegerValue opacity;
+  private final boolean inverted;
 
-  public Mask(MaskMode maskMode, AnimatableShapeValue maskPath, AnimatableIntegerValue opacity) {
+  public Mask(MaskMode maskMode, AnimatableShapeValue maskPath, AnimatableIntegerValue opacity, boolean inverted) {
     this.maskMode = maskMode;
     this.maskPath = maskPath;
     this.opacity = opacity;
+    this.inverted = inverted;
   }
 
   public MaskMode getMaskMode() {
@@ -31,4 +33,8 @@
   public AnimatableIntegerValue getOpacity() {
     return opacity;
   }
+
+  public boolean isInverted() {
+    return inverted;
+  }
 }
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 b7f5622..988408a 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
@@ -19,6 +19,7 @@
 import com.airbnb.lottie.model.KeyPath;
 import com.airbnb.lottie.model.KeyPathElement;
 import com.airbnb.lottie.model.content.Mask;
+import com.airbnb.lottie.model.content.ShapeData;
 import com.airbnb.lottie.value.LottieValueCallback;
 
 import java.util.ArrayList;
@@ -31,14 +32,14 @@
    * These flags were in Canvas but they were deprecated and removed.
    * TODO: test removing these on older versions of Android.
    */
-    private static final int CLIP_SAVE_FLAG = 0x02;
-    private static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;
-    private static final int MATRIX_SAVE_FLAG = 0x01;
-    private static final int SAVE_FLAGS = CLIP_SAVE_FLAG | CLIP_TO_LAYER_SAVE_FLAG | MATRIX_SAVE_FLAG;
+  private static final int CLIP_SAVE_FLAG = 0x02;
+  private static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;
+  private static final int MATRIX_SAVE_FLAG = 0x01;
+  private static final int SAVE_FLAGS = CLIP_SAVE_FLAG | CLIP_TO_LAYER_SAVE_FLAG | MATRIX_SAVE_FLAG;
 
   @Nullable
   static BaseLayer forModel(
-    Layer layerModel, LottieDrawable drawable, LottieComposition composition) {
+      Layer layerModel, LottieDrawable drawable, LottieComposition composition) {
     switch (layerModel.getLayerType()) {
       case SHAPE:
         return new ShapeLayer(drawable, layerModel);
@@ -64,10 +65,14 @@
   private final Path path = new Path();
   private final Matrix matrix = new Matrix();
   private final Paint contentPaint = new LPaint(Paint.ANTI_ALIAS_FLAG);
+  private final Paint dstInPaint = new LPaint(Paint.ANTI_ALIAS_FLAG, PorterDuff.Mode.DST_IN);
   private final Paint addMaskPaint = new LPaint(Paint.ANTI_ALIAS_FLAG);
-  private final Paint subtractMaskPaint = new LPaint(Paint.ANTI_ALIAS_FLAG);
+  private final Paint addInvMaskLayerPaint = new LPaint(Paint.ANTI_ALIAS_FLAG);
+  private final Paint addInvMaskPaintClear = new LPaint(Paint.ANTI_ALIAS_FLAG, PorterDuff.Mode.CLEAR);
+  private final Paint subtractMaskStartingPaintNormal = new LPaint(Paint.ANTI_ALIAS_FLAG);
+  private final Paint subtractMaskPaintDstOut = new LPaint(Paint.ANTI_ALIAS_FLAG, PorterDuff.Mode.DST_OUT);
   private final Paint mattePaint = new LPaint(Paint.ANTI_ALIAS_FLAG);
-  private final Paint clearPaint = new LPaint();
+  private final Paint clearPaint = new LPaint(PorterDuff.Mode.CLEAR);
   private final RectF rect = new RectF();
   private final RectF maskBoundsRect = new RectF();
   private final RectF matteBoundsRect = new RectF();
@@ -76,13 +81,16 @@
   final Matrix boundsMatrix = new Matrix();
   final LottieDrawable lottieDrawable;
   final Layer layerModel;
-  @Nullable private MaskKeyframeAnimation mask;
-  @Nullable private BaseLayer matteLayer;
+  @Nullable
+  private MaskKeyframeAnimation mask;
+  @Nullable
+  private BaseLayer matteLayer;
   /**
    * This should only be used by {@link #buildParentLayerListIfNeeded()}
    * to construct the list of parent layers.
    */
-  @Nullable private BaseLayer parentLayer;
+  @Nullable
+  private BaseLayer parentLayer;
   private List<BaseLayer> parentLayers;
 
   private final List<BaseKeyframeAnimation<?, ?>> animations = new ArrayList<>();
@@ -93,9 +101,8 @@
     this.lottieDrawable = lottieDrawable;
     this.layerModel = layerModel;
     drawTraceName = layerModel.getName() + "#draw";
-    clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
-    addMaskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
-    subtractMaskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+    addMaskPaint.setColor(Color.BLUE);
+    subtractMaskStartingPaintNormal.setColor(Color.BLACK);
     if (layerModel.getMatteType() == Layer.MatteType.INVERT) {
       mattePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
     } else {
@@ -120,7 +127,8 @@
     setupInOutAnimations();
   }
 
-  @Override public void onValueChanged() {
+  @Override
+  public void onValueChanged() {
     invalidateSelf();
   }
 
@@ -146,7 +154,8 @@
           new FloatKeyframeAnimation(layerModel.getInOutKeyframes());
       inOutAnimation.setIsDiscrete();
       inOutAnimation.addUpdateListener(new BaseKeyframeAnimation.AnimationListener() {
-        @Override public void onValueChanged() {
+        @Override
+        public void onValueChanged() {
           setVisible(inOutAnimation.getFloatValue() == 1f);
         }
       });
@@ -176,8 +185,10 @@
     animations.add(newAnimation);
   }
 
-  @CallSuper @Override public void getBounds(
-          RectF outBounds, Matrix parentMatrix, boolean applyParents) {
+  @CallSuper
+  @Override
+  public void getBounds(
+      RectF outBounds, Matrix parentMatrix, boolean applyParents) {
     rect.set(0, 0, 0, 0);
     buildParentLayerListIfNeeded();
     boundsMatrix.set(parentMatrix);
@@ -308,9 +319,10 @@
           // canvas so we can't use the mask bounds.
           return;
         case MASK_MODE_INTERSECT:
-          // TODO
-          return;
         case MASK_MODE_ADD:
+          if (mask.isInverted()) {
+            return;
+          }
         default:
           path.computeBounds(tempMaskBoundsRect, false);
           // As we iterate through the masks, we want to calculate the union region of the masks.
@@ -320,10 +332,10 @@
             maskBoundsRect.set(tempMaskBoundsRect);
           } else {
             maskBoundsRect.set(
-              Math.min(maskBoundsRect.left, tempMaskBoundsRect.left),
-              Math.min(maskBoundsRect.top, tempMaskBoundsRect.top),
-              Math.max(maskBoundsRect.right, tempMaskBoundsRect.right),
-              Math.max(maskBoundsRect.bottom, tempMaskBoundsRect.bottom)
+                Math.min(maskBoundsRect.left, tempMaskBoundsRect.left),
+                Math.min(maskBoundsRect.top, tempMaskBoundsRect.top),
+                Math.max(maskBoundsRect.right, tempMaskBoundsRect.right),
+                Math.max(maskBoundsRect.bottom, tempMaskBoundsRect.bottom)
             );
           }
       }
@@ -357,67 +369,95 @@
   abstract void drawLayer(Canvas canvas, Matrix parentMatrix, int parentAlpha);
 
   private void applyMasks(Canvas canvas, Matrix matrix) {
-    applyMasks(canvas, matrix, Mask.MaskMode.MASK_MODE_ADD);
-    // Treat intersect masks like add masks. This is not correct but it's closer.
-    applyMasks(canvas, matrix, Mask.MaskMode.MASK_MODE_INTERSECT);
-    applyMasks(canvas, matrix, Mask.MaskMode.MASK_MODE_SUBTRACT);
-  }
-
-  private void applyMasks(Canvas canvas, Matrix matrix,
-      Mask.MaskMode maskMode) {
-    Paint paint;
-    switch (maskMode) {
-      case MASK_MODE_SUBTRACT:
-        paint = subtractMaskPaint;
-        break;
-      case MASK_MODE_INTERSECT:
-      case MASK_MODE_ADD:
-      default:
-        // As a hack, we treat all non-subtract masks like add masks. This is not correct but it's
-        // better than nothing.
-        paint = addMaskPaint;
-    }
-
-    //noinspection ConstantConditions
-    int size = mask.getMasks().size();
-
-    boolean hasMask = false;
-    for (int i = 0; i < size; i++) {
-      if (mask.getMasks().get(i).getMaskMode() == maskMode) {
-        hasMask = true;
-        break;
-      }
-    }
-    if (!hasMask) {
-      return;
-    }
-
-    L.beginSection("Layer#drawMask");
     L.beginSection("Layer#saveLayer");
-    saveLayerCompat(canvas, rect, paint, false);
+    saveLayerCompat(canvas, rect, dstInPaint, false);
+//    canvas.drawRect(rect.left, rect.top, rect.right, rect.bottom, subtractMaskStartingPaintNormal);
     L.endSection("Layer#saveLayer");
-    clearCanvas(canvas);
-
-    for (int i = 0; i < size; i++) {
+    for (int i = 0; i < mask.getMasks().size(); i++) {
       Mask mask = this.mask.getMasks().get(i);
-      if (mask.getMaskMode() != maskMode) {
-        continue;
+      BaseKeyframeAnimation<ShapeData, Path> maskAnimation = this.mask.getMaskAnimations().get(i);
+      BaseKeyframeAnimation<Integer, Integer> opacityAnimation = this.mask.getOpacityAnimations().get(i);
+      switch (mask.getMaskMode()) {
+        case MASK_MODE_ADD:
+          if (mask.isInverted()) {
+            applyInvertedAddMask(canvas, matrix, mask, maskAnimation, opacityAnimation);
+          } else {
+            applyAddMask(canvas, matrix, mask, maskAnimation, opacityAnimation);
+          }
+          break;
+        case MASK_MODE_SUBTRACT:
+          if (i == 0) {
+            // TODO: make a paint for this.
+            Paint paint = new Paint();
+            paint.setColor(Color.BLACK);
+            canvas.drawRect(rect, paint);
+          }
+          if (mask.isInverted()) {
+            applyInvertedSubtractMask(canvas, matrix, mask, maskAnimation, opacityAnimation);
+          } else {
+            applySubtractMask(canvas, matrix, mask, maskAnimation, opacityAnimation);
+          }
+          break;
+        case MASK_MODE_INTERSECT:
+          applyIntersectMask(canvas, matrix, mask, maskAnimation, opacityAnimation);
+          break;
       }
-      BaseKeyframeAnimation<?, Path> maskAnimation = this.mask.getMaskAnimations().get(i);
-      Path maskPath = maskAnimation.getValue();
-      path.set(maskPath);
-      path.transform(matrix);
-      BaseKeyframeAnimation<Integer, Integer> opacityAnimation =
-          this.mask.getOpacityAnimations().get(i);
-      int alpha = contentPaint.getAlpha();
-      contentPaint.setAlpha((int) (opacityAnimation.getValue() * 2.55f));
-      canvas.drawPath(path, contentPaint);
-      contentPaint.setAlpha(alpha);
     }
     L.beginSection("Layer#restoreLayer");
     canvas.restore();
     L.endSection("Layer#restoreLayer");
-    L.endSection("Layer#drawMask");
+  }
+
+  private void applyAddMask(Canvas canvas, Matrix matrix, Mask mask,
+      BaseKeyframeAnimation<ShapeData, Path> maskAnimation, BaseKeyframeAnimation<Integer, Integer> opacityAnimation) {
+    Path maskPath = maskAnimation.getValue();
+    path.set(maskPath);
+    path.transform(matrix);
+    addMaskPaint.setAlpha((int) (opacityAnimation.getValue() * 2.55f));
+    canvas.drawPath(path, addMaskPaint);
+  }
+
+  private void applyInvertedAddMask(Canvas canvas, Matrix matrix, Mask mask,
+      BaseKeyframeAnimation<ShapeData, Path> maskAnimation, BaseKeyframeAnimation<Integer, Integer> opacityAnimation) {
+    saveLayerCompat(canvas, rect, addInvMaskLayerPaint, true);
+    canvas.drawRect(rect, addInvMaskLayerPaint);
+    Path maskPath = maskAnimation.getValue();
+    path.set(maskPath);
+    path.transform(matrix);
+    addMaskPaint.setAlpha((int) (opacityAnimation.getValue() * 2.55f));
+    canvas.drawPath(path, addInvMaskPaintClear);
+    canvas.restore();
+  }
+
+  private void applySubtractMask(Canvas canvas, Matrix matrix, Mask mask,
+      BaseKeyframeAnimation<ShapeData, Path> maskAnimation, BaseKeyframeAnimation<Integer, Integer> opacityAnimation) {
+    Path maskPath = maskAnimation.getValue();
+    path.set(maskPath);
+    path.transform(matrix);
+    canvas.drawPath(path, subtractMaskPaintDstOut);
+  }
+
+  private void applyInvertedSubtractMask(Canvas canvas, Matrix matrix, Mask mask,
+      BaseKeyframeAnimation<ShapeData, Path> maskAnimation, BaseKeyframeAnimation<Integer, Integer> opacityAnimation) {
+    saveLayerCompat(canvas, rect, subtractMaskPaintDstOut, true);
+    canvas.drawRect(rect, subtractMaskStartingPaintNormal);
+    subtractMaskPaintDstOut.setAlpha((int) (opacityAnimation.getValue() * 2.55f));
+    Path maskPath = maskAnimation.getValue();
+    path.set(maskPath);
+    path.transform(matrix);
+    canvas.drawPath(path, subtractMaskPaintDstOut);
+    canvas.restore();
+  }
+
+  private void applyIntersectMask(Canvas canvas, Matrix matrix, Mask mask,
+      BaseKeyframeAnimation<ShapeData, Path> maskAnimation, BaseKeyframeAnimation<Integer, Integer> opacityAnimation) {
+    saveLayerCompat(canvas, rect, dstInPaint, true);
+    Path maskPath = maskAnimation.getValue();
+    path.set(maskPath);
+    path.transform(matrix);
+    contentPaint.setAlpha((int) (opacityAnimation.getValue() * 2.55f));
+    canvas.drawPath(path, contentPaint);
+    canvas.restore();
   }
 
   boolean hasMasksOnThisLayer() {
@@ -469,15 +509,18 @@
     }
   }
 
-  @Override public String getName() {
+  @Override
+  public String getName() {
     return layerModel.getName();
   }
 
-  @Override public void setContents(List<Content> contentsBefore, List<Content> contentsAfter) {
+  @Override
+  public void setContents(List<Content> contentsBefore, List<Content> contentsAfter) {
     // Do nothing
   }
 
-  @Override public void resolveKeyPath(
+  @Override
+  public void resolveKeyPath(
       KeyPath keyPath, int depth, List<KeyPath> accumulator, KeyPath currentPartialKeyPath) {
     if (!keyPath.matches(getName(), depth)) {
       return;
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 32e77de..a25300e 100644
--- a/lottie/src/main/java/com/airbnb/lottie/parser/MaskParser.java
+++ b/lottie/src/main/java/com/airbnb/lottie/parser/MaskParser.java
@@ -20,6 +20,7 @@
     Mask.MaskMode maskMode = null;
     AnimatableShapeValue maskPath = null;
     AnimatableIntegerValue opacity = null;
+    boolean inverted = false;
 
     reader.beginObject();
     while (reader.hasNext()) {
@@ -49,13 +50,16 @@
         case "o":
           opacity = AnimatableValueParser.parseInteger(reader, composition);
           break;
+        case "inv":
+          inverted = reader.nextBoolean();
+          break;
         default:
           reader.skipValue();
       }
     }
     reader.endObject();
 
-    return new Mask(maskMode, maskPath, opacity);
+    return new Mask(maskMode, maskPath, opacity, inverted);
   }
 
 }