blob: b69d713495f27703209bbdbf12d2a7697117e785 [file] [log] [blame]
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);
}
}