@Override
  public void draw(Canvas canvas, Matrix parentMatrix, int parentAlpha, @Nullable DropShadow shadowToApply) {
    L.beginSection(drawTraceName);
    if (!visible || layerModel.isHidden()) {
      L.endSection(drawTraceName);
      return;
    }
    buildParentLayerListIfNeeded();
    if (L.isTraceEnabled()) {
      L.beginSection("Layer#parentMatrix");
    }
    matrix.reset();
    matrix.set(parentMatrix);
    for (int i = parentLayers.size() - 1; i >= 0; i--) {
      matrix.preConcat(parentLayers.get(i).transform.getMatrix());
    }
    if (L.isTraceEnabled()) {
      L.endSection("Layer#parentMatrix");
    }
    // It is unclear why but getting the opacity here would sometimes NPE.
    // The extra code here is designed to avoid this.
    // https://github.com/airbnb/lottie-android/issues/2083
    int opacity = 100;
    BaseKeyframeAnimation<?, Integer> opacityAnimation = transform.getOpacity();
    if (opacityAnimation != null) {
      Integer opacityValue = opacityAnimation.getValue();
      if (opacityValue != null) {
        opacity = opacityValue;
      }
    }
    int alpha = (int) ((parentAlpha / 255f * (float) opacity / 100f) * 255);
    if (!hasMatteOnThisLayer() && !hasMasksOnThisLayer() && getBlendMode() == LBlendMode.NORMAL) {
      matrix.preConcat(transform.getMatrix());
      if (L.isTraceEnabled()) {
        L.beginSection("Layer#drawLayer");
      }
      drawLayer(canvas, matrix, alpha, shadowToApply);
      if (L.isTraceEnabled()) {
        L.endSection("Layer#drawLayer");
      }
      recordRenderTime(L.endSection(drawTraceName));
      return;
    }

    if (L.isTraceEnabled()) {
      L.beginSection("Layer#computeBounds");
    }
    getBounds(rect, matrix, false);

    intersectBoundsWithMatte(rect, parentMatrix);

    matrix.preConcat(transform.getMatrix());
    intersectBoundsWithMask(rect, matrix);

    // Intersect the mask and matte rect with the canvas bounds.
    // If the canvas has a transform, then we need to transform its bounds by its matrix
    // so that we know the coordinate space that the canvas is showing.
    canvasBounds.set(0f, 0f, canvas.getWidth(), canvas.getHeight());
    //noinspection deprecation
    canvas.getMatrix(canvasMatrix);
    if (!canvasMatrix.isIdentity()) {
      canvasMatrix.invert(canvasMatrix);
      canvasMatrix.mapRect(canvasBounds);
    }
    if (!rect.intersect(canvasBounds)) {
      rect.set(0, 0, 0, 0);
    }

    if (L.isTraceEnabled()) {
      L.endSection("Layer#computeBounds");
    }

    // Ensure that what we are drawing is >=1px of width and height.
    // On older devices, drawing to an offscreen buffer of <1px would draw back as a black bar.
    // https://github.com/airbnb/lottie-android/issues/1625
    if (rect.width() >= 1f && rect.height() >= 1f) {
      if (L.isTraceEnabled()) {
        L.beginSection("Layer#saveLayer");
      }
      contentPaint.setAlpha(255);
      PaintCompat.setBlendMode(contentPaint, getBlendMode().toNativeBlendMode());

      Utils.saveLayerCompat(canvas, rect, contentPaint);
      if (L.isTraceEnabled()) {
        L.endSection("Layer#saveLayer");
      }

      // Clear the off screen buffer. This is necessary for some phones.
      if (getBlendMode() != LBlendMode.MULTIPLY) {
        clearCanvas(canvas);
      } else {
        // Due to the difference between PorterDuffMode.MULTIPLY (which we use for compatibility
        // with Android < Q) and BlendMode.MULTIPLY (which is the correct, alpha-blended mode),
        // we will alpha-blend the contents of this layer on top of a white background before
        // we multiply it with the opaque substrate below (with canvas.restore()).
        //
        // Since white is the identity color for multiplication, this will behave as if we
        // had correctly performed an alpha-blended multiply (such as BlendMode.MULTIPLY), but
        // will work pre-Q as well.
        if (solidWhitePaint == null) {
          solidWhitePaint = new LPaint();
          solidWhitePaint.setColor(0xffffffff);
        }
        canvas.drawRect(rect.left - 1, rect.top - 1, rect.right + 1, rect.bottom + 1, solidWhitePaint);
      }

      if (L.isTraceEnabled()) {
        L.beginSection("Layer#drawLayer");
      }
      drawLayer(canvas, matrix, alpha, shadowToApply);
      if (L.isTraceEnabled()) {
        L.endSection("Layer#drawLayer");
      }

      if (hasMasksOnThisLayer()) {
        applyMasks(canvas, matrix);
      }

      if (hasMatteOnThisLayer()) {
        if (L.isTraceEnabled()) {
          L.beginSection("Layer#drawMatte");
          L.beginSection("Layer#saveLayer");
        }
        Utils.saveLayerCompat(canvas, rect, mattePaint, SAVE_FLAGS);
        if (L.isTraceEnabled()) {
          L.endSection("Layer#saveLayer");
        }
        clearCanvas(canvas);
        //noinspection ConstantConditions
        matteLayer.draw(canvas, parentMatrix, parentAlpha, null);
        if (L.isTraceEnabled()) {
          L.beginSection("Layer#restoreLayer");
        }
        canvas.restore();
        if (L.isTraceEnabled()) {
          L.endSection("Layer#restoreLayer");
          L.endSection("Layer#drawMatte");
        }
      }

      if (L.isTraceEnabled()) {
        L.beginSection("Layer#restoreLayer");
      }
      canvas.restore();
      if (L.isTraceEnabled()) {
        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));
  }
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.
<p>
DO NOT leave this enabled in production.
lottie/src/main/java/com/airbnb/lottie/model/layer/BaseLayer.java