Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a few potential NPE race conditions #1917

Merged
merged 1 commit into from
Nov 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
Original file line number Diff line number Diff line change
Expand Up @@ -1194,22 +1194,25 @@ public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
* If the composition is larger than the canvas, we have to use a different method to scale it up.
* See the comments in {@link #draw(Canvas)} for more info.
*/
private float getMaxScale(@NonNull Canvas canvas) {
private float getMaxScale(@NonNull Canvas canvas, LottieComposition composition) {
float maxScaleX = canvas.getWidth() / (float) composition.getBounds().width();
float maxScaleY = canvas.getHeight() / (float) composition.getBounds().height();
return Math.min(maxScaleX, maxScaleY);
}

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void draw(Canvas canvas, Matrix matrix) {
CompositionLayer compositionLayer = this.compositionLayer;
if (compositionLayer == null) {
return;
}
compositionLayer.draw(canvas, matrix, alpha);
}

private void drawWithNewAspectRatio(Canvas canvas) {
if (compositionLayer == null) {
CompositionLayer compositionLayer = this.compositionLayer;
LottieComposition composition = this.composition;
if (compositionLayer == null || composition == null) {
return;
}

Expand Down Expand Up @@ -1252,13 +1255,15 @@ private void drawWithNewAspectRatio(Canvas canvas) {
}

private void drawWithOriginalAspectRatio(Canvas canvas) {
if (compositionLayer == null) {
CompositionLayer compositionLayer = this.compositionLayer;
LottieComposition composition = this.composition;
if (compositionLayer == null || composition == null) {
return;
}

float scale = this.scale;
float extraScale = 1f;
float maxScale = getMaxScale(canvas);
float maxScale = getMaxScale(canvas, composition);
if (scale > maxScale) {
scale = maxScale;
extraScale = this.scale / scale;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import android.graphics.Matrix;
import android.graphics.PointF;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.airbnb.lottie.model.animatable.AnimatableTransform;
Expand All @@ -33,11 +32,11 @@ public class TransformKeyframeAnimation {
private final Matrix skewMatrix3;
private final float[] skewValues;

@NonNull private BaseKeyframeAnimation<PointF, PointF> anchorPoint;
@NonNull private BaseKeyframeAnimation<?, PointF> position;
@NonNull private BaseKeyframeAnimation<ScaleXY, ScaleXY> scale;
@NonNull private BaseKeyframeAnimation<Float, Float> rotation;
@NonNull private BaseKeyframeAnimation<Integer, Integer> opacity;
@Nullable private BaseKeyframeAnimation<PointF, PointF> anchorPoint;
@Nullable private BaseKeyframeAnimation<?, PointF> position;
@Nullable private BaseKeyframeAnimation<ScaleXY, ScaleXY> scale;
@Nullable private BaseKeyframeAnimation<Float, Float> rotation;
@Nullable private BaseKeyframeAnimation<Integer, Integer> opacity;
@Nullable private FloatKeyframeAnimation skew;
@Nullable private FloatKeyframeAnimation skewAngle;

Expand Down Expand Up @@ -167,25 +166,28 @@ public void setProgress(float progress) {

public Matrix getMatrix() {
matrix.reset();
BaseKeyframeAnimation<?, PointF> position = this.position;
if (position != null) {
PointF position = this.position.getValue();
if (position.x != 0 || position.y != 0) {
matrix.preTranslate(position.x, position.y);
PointF positionValue = position.getValue();
if (positionValue.x != 0 || positionValue.y != 0) {
matrix.preTranslate(positionValue.x, positionValue.y);
}
}

BaseKeyframeAnimation<Float, Float> rotation = this.rotation;
if (rotation != null) {
float rotation;
if (this.rotation instanceof ValueCallbackKeyframeAnimation) {
rotation = this.rotation.getValue();
float rotationValue;
if (rotation instanceof ValueCallbackKeyframeAnimation) {
rotationValue = rotation.getValue();
} else {
rotation = ((FloatKeyframeAnimation) this.rotation).getFloatValue();
rotationValue = ((FloatKeyframeAnimation) rotation).getFloatValue();
}
if (rotation != 0f) {
matrix.preRotate(rotation);
if (rotationValue != 0f) {
matrix.preRotate(rotationValue);
}
}

FloatKeyframeAnimation skew = this.skew;
if (skew != null) {
float mCos = skewAngle == null ? 0f : (float) Math.cos(Math.toRadians(-skewAngle.getFloatValue() + 90));
float mSin = skewAngle == null ? 1f : (float) Math.sin(Math.toRadians(-skewAngle.getFloatValue() + 90));
Expand Down Expand Up @@ -216,17 +218,19 @@ public Matrix getMatrix() {
matrix.preConcat(skewMatrix3);
}

BaseKeyframeAnimation<ScaleXY, ScaleXY> scale = this.scale;
if (scale != null) {
ScaleXY scaleTransform = this.scale.getValue();
ScaleXY scaleTransform = scale.getValue();
if (scaleTransform.getScaleX() != 1f || scaleTransform.getScaleY() != 1f) {
matrix.preScale(scaleTransform.getScaleX(), scaleTransform.getScaleY());
}
}

BaseKeyframeAnimation<PointF, PointF> anchorPoint = this.anchorPoint;
if (anchorPoint != null) {
PointF anchorPoint = this.anchorPoint.getValue();
if (anchorPoint.x != 0 || anchorPoint.y != 0) {
matrix.preTranslate(-anchorPoint.x, -anchorPoint.y);
PointF anchorPointValue = anchorPoint.getValue();
if (anchorPointValue.x != 0 || anchorPointValue.y != 0) {
matrix.preTranslate(-anchorPointValue.x, -anchorPointValue.y);
}
}

Expand Down Expand Up @@ -271,13 +275,13 @@ public Matrix getMatrixForRepeater(float amount) {
public <T> boolean applyValueCallback(T property, @Nullable LottieValueCallback<T> callback) {
if (property == TRANSFORM_ANCHOR_POINT) {
if (anchorPoint == null) {
anchorPoint = new ValueCallbackKeyframeAnimation(callback, new PointF());
anchorPoint = new ValueCallbackKeyframeAnimation<>((LottieValueCallback<PointF>) callback, new PointF());
} else {
anchorPoint.setValueCallback((LottieValueCallback<PointF>) callback);
}
} else if (property == TRANSFORM_POSITION) {
if (position == null) {
position = new ValueCallbackKeyframeAnimation(callback, new PointF());
position = new ValueCallbackKeyframeAnimation<>((LottieValueCallback<PointF>) callback, new PointF());
} else {
position.setValueCallback((LottieValueCallback<PointF>) callback);
}
Expand All @@ -287,42 +291,42 @@ public <T> boolean applyValueCallback(T property, @Nullable LottieValueCallback<
((SplitDimensionPathKeyframeAnimation) position).setYValueCallback((LottieValueCallback<Float>) callback);
} else if (property == TRANSFORM_SCALE) {
if (scale == null) {
scale = new ValueCallbackKeyframeAnimation(callback, new ScaleXY());
scale = new ValueCallbackKeyframeAnimation<>((LottieValueCallback<ScaleXY>) callback, new ScaleXY());
} else {
scale.setValueCallback((LottieValueCallback<ScaleXY>) callback);
}
} else if (property == TRANSFORM_ROTATION) {
if (rotation == null) {
rotation = new ValueCallbackKeyframeAnimation(callback, 0f);
rotation = new ValueCallbackKeyframeAnimation<>((LottieValueCallback<Float>) callback, 0f);
} else {
rotation.setValueCallback((LottieValueCallback<Float>) callback);
}
} else if (property == TRANSFORM_OPACITY) {
if (opacity == null) {
opacity = new ValueCallbackKeyframeAnimation(callback, 100);
opacity = new ValueCallbackKeyframeAnimation<>((LottieValueCallback<Integer>) callback, 100);
} else {
opacity.setValueCallback((LottieValueCallback<Integer>) callback);
}
} else if (property == TRANSFORM_START_OPACITY && startOpacity != null) {
} else if (property == TRANSFORM_START_OPACITY) {
if (startOpacity == null) {
startOpacity = new ValueCallbackKeyframeAnimation(callback, 100);
startOpacity = new ValueCallbackKeyframeAnimation<>((LottieValueCallback<Float>) callback, 100f);
} else {
startOpacity.setValueCallback((LottieValueCallback<Float>) callback);
}
} else if (property == TRANSFORM_END_OPACITY && endOpacity != null) {
} else if (property == TRANSFORM_END_OPACITY) {
if (endOpacity == null) {
endOpacity = new ValueCallbackKeyframeAnimation(callback, 100);
endOpacity = new ValueCallbackKeyframeAnimation<>((LottieValueCallback<Float>) callback, 100f);
} else {
endOpacity.setValueCallback((LottieValueCallback<Float>) callback);
}
} else if (property == TRANSFORM_SKEW && skew != null) {
} else if (property == TRANSFORM_SKEW) {
if (skew == null) {
skew = new FloatKeyframeAnimation(Collections.singletonList(new Keyframe<Float>(0f)));
skew = new FloatKeyframeAnimation(Collections.singletonList(new Keyframe<>(0f)));
}
skew.setValueCallback((LottieValueCallback<Float>) callback);
} else if (property == TRANSFORM_SKEW_ANGLE && skewAngle != null) {
} else if (property == TRANSFORM_SKEW_ANGLE) {
if (skewAngle == null) {
skewAngle = new FloatKeyframeAnimation(Collections.singletonList(new Keyframe<Float>(0f)));
skewAngle = new FloatKeyframeAnimation(Collections.singletonList(new Keyframe<>(0f)));
}
skewAngle.setValueCallback((LottieValueCallback<Float>) callback);
} else {
Expand Down