content: package com.airbnb.lottie.animation.content;
  
  import android.annotation.TargetApi;
  import android.graphics.Path;
  import android.os.Build;
  
  import com.airbnb.lottie.model.content.MergePaths;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.ListIterator;
  
  @TargetApi(Build.VERSION_CODES.KITKAT)
  public class MergePathsContent implements PathContent, GreedyContent {
    private final Path firstPath = new Path();
    private final Path remainderPath = new Path();
    private final Path path = new Path();
  
    private final String name;
    private final List<PathContent> pathContents = new ArrayList<>();
    private final MergePaths mergePaths;
  
    public MergePathsContent(MergePaths mergePaths) {
      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
        throw new IllegalStateException("Merge paths are not supported pre-KitKat.");
      }
      name = mergePaths.getName();
      this.mergePaths = mergePaths;
    }
  
    @Override public void absorbContent(ListIterator<Content> contents) {
      // Fast forward the iterator until after this content.
      //noinspection StatementWithEmptyBody
      while (contents.hasPrevious() && contents.previous() != this) {
      }
      while (contents.hasPrevious()) {
        Content content = contents.previous();
        if (content instanceof PathContent) {
          pathContents.add((PathContent) content);
          contents.remove();
        }
      }
    }
  
    @Override public void setContents(List<Content> contentsBefore, List<Content> contentsAfter) {
      for (int i = 0; i < pathContents.size(); i++) {
        pathContents.get(i).setContents(contentsBefore, contentsAfter);
      }
    }
  
    @Override public Path getPath() {
      path.reset();
  
      if (mergePaths.isHidden()) {
        return path;
      }
  
      switch (mergePaths.getMode()) {
        case MERGE:
          addPaths();
          break;
        case ADD:
          opFirstPathWithRest(Path.Op.UNION);
          break;
        case SUBTRACT:
          opFirstPathWithRest(Path.Op.REVERSE_DIFFERENCE);
          break;
        case INTERSECT:
          opFirstPathWithRest(Path.Op.INTERSECT);
          break;
        case EXCLUDE_INTERSECTIONS:
          opFirstPathWithRest(Path.Op.XOR);
          break;
      }
  
      return path;
    }
  
    @Override public String getName() {
      return name;
    }
  
    private void addPaths() {
      for (int i = 0; i < pathContents.size(); i++) {
        path.addPath(pathContents.get(i).getPath());
      }
    }
  
    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void opFirstPathWithRest(Path.Op op) {
      remainderPath.reset();
      firstPath.reset();
  
      for (int i = pathContents.size() - 1; i >= 1; i--) {
        PathContent content = pathContents.get(i);
  
        if (content instanceof ContentGroup) {
          List<PathContent> pathList = ((ContentGroup) content).getPathList();
          for (int j = pathList.size() - 1; j >= 0; j--) {
            Path path = pathList.get(j).getPath();
            path.transform(((ContentGroup) content).getTransformationMatrix());
            this.remainderPath.addPath(path);
          }
        } else {
          remainderPath.addPath(content.getPath());
        }
      }
  
      PathContent lastContent = pathContents.get(0);
      if (lastContent instanceof ContentGroup) {
        List<PathContent> pathList = ((ContentGroup) lastContent).getPathList();
        for (int j = 0; j < pathList.size(); j++) {
          Path path = pathList.get(j).getPath();
          path.transform(((ContentGroup) lastContent).getTransformationMatrix());
          this.firstPath.addPath(path);
        }
      } else {
        firstPath.set(lastContent.getPath());
      }
  
      path.op(firstPath, remainderPath, op);
    }
  }
  