• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.airbnb.lottie.utils;
2 
3 import android.graphics.Path;
4 import android.graphics.PointF;
5 
6 import androidx.annotation.FloatRange;
7 
8 import com.airbnb.lottie.animation.content.KeyPathElementContent;
9 import com.airbnb.lottie.model.CubicCurveData;
10 import com.airbnb.lottie.model.KeyPath;
11 import com.airbnb.lottie.model.content.ShapeData;
12 
13 import java.util.List;
14 
15 public class MiscUtils {
16   private static final PointF pathFromDataCurrentPoint = new PointF();
17 
addPoints(PointF p1, PointF p2)18   public static PointF addPoints(PointF p1, PointF p2) {
19     return new PointF(p1.x + p2.x, p1.y + p2.y);
20   }
21 
getPathFromData(ShapeData shapeData, Path outPath)22   public static void getPathFromData(ShapeData shapeData, Path outPath) {
23     outPath.reset();
24     PointF initialPoint = shapeData.getInitialPoint();
25     outPath.moveTo(initialPoint.x, initialPoint.y);
26     pathFromDataCurrentPoint.set(initialPoint.x, initialPoint.y);
27     for (int i = 0; i < shapeData.getCurves().size(); i++) {
28       CubicCurveData curveData = shapeData.getCurves().get(i);
29       PointF cp1 = curveData.getControlPoint1();
30       PointF cp2 = curveData.getControlPoint2();
31       PointF vertex = curveData.getVertex();
32 
33       if (cp1.equals(pathFromDataCurrentPoint) && cp2.equals(vertex)) {
34         // On some phones like Samsung phones, zero valued control points can cause artifacting.
35         // https://github.com/airbnb/lottie-android/issues/275
36         //
37         // This does its best to add a tiny value to the vertex without affecting the final
38         // animation as much as possible.
39         // outPath.rMoveTo(0.01f, 0.01f);
40         outPath.lineTo(vertex.x, vertex.y);
41       } else {
42         outPath.cubicTo(cp1.x, cp1.y, cp2.x, cp2.y, vertex.x, vertex.y);
43       }
44       pathFromDataCurrentPoint.set(vertex.x, vertex.y);
45     }
46     if (shapeData.isClosed()) {
47       outPath.close();
48     }
49   }
50 
lerp(float a, float b, @FloatRange(from = 0f, to = 1f) float percentage)51   public static float lerp(float a, float b, @FloatRange(from = 0f, to = 1f) float percentage) {
52     return a + percentage * (b - a);
53   }
54 
lerp(double a, double b, @FloatRange(from = 0f, to = 1f) double percentage)55   public static double lerp(double a, double b, @FloatRange(from = 0f, to = 1f) double percentage) {
56     return a + percentage * (b - a);
57   }
58 
lerp(int a, int b, @FloatRange(from = 0f, to = 1f) float percentage)59   public static int lerp(int a, int b, @FloatRange(from = 0f, to = 1f) float percentage) {
60     return (int) (a + percentage * (b - a));
61   }
62 
floorMod(float x, float y)63   static int floorMod(float x, float y) {
64     return floorMod((int) x, (int) y);
65   }
66 
floorMod(int x, int y)67   private static int floorMod(int x, int y) {
68     return x - y * floorDiv(x, y);
69   }
70 
floorDiv(int x, int y)71   private static int floorDiv(int x, int y) {
72     int r = x / y;
73     boolean sameSign = (x ^ y) >= 0;
74     int mod = x % y;
75     if (!sameSign && mod != 0) {
76       r--;
77     }
78     return r;
79   }
80 
clamp(int number, int min, int max)81   public static int clamp(int number, int min, int max) {
82     return Math.max(min, Math.min(max, number));
83   }
84 
clamp(float number, float min, float max)85   public static float clamp(float number, float min, float max) {
86     return Math.max(min, Math.min(max, number));
87   }
88 
clamp(double number, double min, double max)89   public static double clamp(double number, double min, double max) {
90     return Math.max(min, Math.min(max, number));
91   }
92 
contains(float number, float rangeMin, float rangeMax)93   public static boolean contains(float number, float rangeMin, float rangeMax) {
94     return number >= rangeMin && number <= rangeMax;
95   }
96 
97   /**
98    * Helper method for any {@link KeyPathElementContent} that will check if the content
99    * fully matches the keypath then will add itself as the final key, resolve it, and add
100    * it to the accumulator list.
101    * <p>
102    * Any {@link KeyPathElementContent} should call through to this as its implementation of
103    * {@link KeyPathElementContent#resolveKeyPath(KeyPath, int, List, KeyPath)}.
104    */
resolveKeyPath(KeyPath keyPath, int depth, List<KeyPath> accumulator, KeyPath currentPartialKeyPath, KeyPathElementContent content)105   public static void resolveKeyPath(KeyPath keyPath, int depth, List<KeyPath> accumulator,
106       KeyPath currentPartialKeyPath, KeyPathElementContent content) {
107     if (keyPath.fullyResolvesTo(content.getName(), depth)) {
108       currentPartialKeyPath = currentPartialKeyPath.addKey(content.getName());
109       accumulator.add(currentPartialKeyPath.resolve(content));
110     }
111   }
112 }
113