/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.drawee.drawable;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import com.facebook.testing.robolectric.v2.WithTestDefaultsRunner;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static com.facebook.drawee.drawable.ScalingUtils.ScaleType;
import static org.mockito.Mockito.*;
@RunWith(WithTestDefaultsRunner.class)
public class ScaleTypeDrawableTest {
private Drawable mUnderlyingDrawable = mock(Drawable.class);
private PointF mFocusPoint = new PointF(0.1f, 0.4f);
private Drawable.Callback mCallback = mock(Drawable.Callback.class);
private Rect mViewBounds = new Rect(10, 10, 410, 310);
private ScaleTypeDrawable mScaleTypeDrawable;
@Before
public void setUp() {
mScaleTypeDrawable = new ScaleTypeDrawable(mUnderlyingDrawable, ScaleType.CENTER);
mScaleTypeDrawable.setCallback(mCallback);
}
@Test
public void testIntrinsicDimensions() {
when(mUnderlyingDrawable.getIntrinsicWidth()).thenReturn(100);
when(mUnderlyingDrawable.getIntrinsicHeight()).thenReturn(200);
Assert.assertEquals(100, mScaleTypeDrawable.getIntrinsicWidth());
Assert.assertEquals(200, mScaleTypeDrawable.getIntrinsicHeight());
}
@Test
public void testBasics() {
// initial state
Assert.assertEquals(mUnderlyingDrawable, mScaleTypeDrawable.getCurrent());
Assert.assertEquals(ScaleType.CENTER, mScaleTypeDrawable.getScaleType());
Assert.assertEquals(null, mScaleTypeDrawable.getFocusPoint());
mScaleTypeDrawable.setScaleType(ScaleType.FIT_XY);
Assert.assertEquals(ScaleType.FIT_XY, mScaleTypeDrawable.getScaleType());
mScaleTypeDrawable.setScaleType(ScaleType.FOCUS_CROP);
Assert.assertEquals(ScaleType.FOCUS_CROP, mScaleTypeDrawable.getScaleType());
mScaleTypeDrawable.setFocusPoint(mFocusPoint);
AndroidGraphicsTestUtils.assertEquals(mFocusPoint, mScaleTypeDrawable.getFocusPoint(), 0f);
}
@Test
public void testConfigureBounds_NoIntrinsicDimensions() {
for (ScaleType scaleType : ScaleType.values()) {
System.out.println("testConfigureBounds_NoIntrinsicDimensions: " + scaleType);
testConfigureBounds_NoIntrinsicDimensions(scaleType, mViewBounds);
}
}
private void testConfigureBounds_NoIntrinsicDimensions(ScaleType scaleType, Rect viewBounds) {
mScaleTypeDrawable.setScaleType(scaleType);
mScaleTypeDrawable.setBounds(viewBounds);
reset(mUnderlyingDrawable);
when(mUnderlyingDrawable.getIntrinsicWidth()).thenReturn(-1);
when(mUnderlyingDrawable.getIntrinsicHeight()).thenReturn(-1);
mScaleTypeDrawable.configureBounds();
verify(mUnderlyingDrawable).getIntrinsicWidth();
verify(mUnderlyingDrawable).getIntrinsicHeight();
verify(mUnderlyingDrawable).setBounds(viewBounds);
Assert.assertEquals(null, mScaleTypeDrawable.mDrawMatrix);
verifyNoMoreInteractions(mUnderlyingDrawable);
}
@Test
public void testConfigureBounds_SameAsView() {
for (ScaleType scaleType : ScaleType.values()) {
System.out.println("testConfigureBounds_SameAsView: " + scaleType);
testConfigureBounds_SameAsView(scaleType, mViewBounds);
}
}
private void testConfigureBounds_SameAsView(ScaleType scaleType, Rect viewBounds) {
mScaleTypeDrawable.setScaleType(scaleType);
mScaleTypeDrawable.setBounds(viewBounds);
reset(mUnderlyingDrawable);
when(mUnderlyingDrawable.getIntrinsicWidth()).thenReturn(viewBounds.width());
when(mUnderlyingDrawable.getIntrinsicHeight()).thenReturn(viewBounds.height());
mScaleTypeDrawable.configureBounds();
verify(mUnderlyingDrawable).getIntrinsicWidth();
verify(mUnderlyingDrawable).getIntrinsicHeight();
verify(mUnderlyingDrawable).setBounds(viewBounds);
Assert.assertEquals(null, mScaleTypeDrawable.mDrawMatrix);
verifyNoMoreInteractions(mUnderlyingDrawable);
}
@Test
public void testConfigureBounds_FIT_XY() {
mScaleTypeDrawable.setScaleType(ScaleType.FIT_XY);
mScaleTypeDrawable.setBounds(mViewBounds);
reset(mUnderlyingDrawable);
when(mUnderlyingDrawable.getIntrinsicWidth()).thenReturn(40);
when(mUnderlyingDrawable.getIntrinsicHeight()).thenReturn(30);
mScaleTypeDrawable.configureBounds();
verify(mUnderlyingDrawable).getIntrinsicWidth();
verify(mUnderlyingDrawable).getIntrinsicHeight();
verify(mUnderlyingDrawable).setBounds(mViewBounds);
Assert.assertEquals(null, mScaleTypeDrawable.mDrawMatrix);
verifyNoMoreInteractions(mUnderlyingDrawable);
}
/**
* Underlying drawable's aspect ratio is bigger than view's, so it has to be slided horizontally
* after scaling.
*/
@Test
public void testConfigureBounds_CENTER_CROP_H() {
Rect bounds = new Rect(10, 10, 410, 310);
int width = 400;
int height = 200;
Matrix expectedMatrix = new Matrix();
expectedMatrix.setScale(1.5f, 1.5f);
expectedMatrix.postTranslate(-89, 10);
testConfigureBounds(bounds, width, height, ScaleType.CENTER_CROP, null, expectedMatrix);
}
/**
* Underlying drawable's aspect ratio is smaller than view's, so it has to be slided vertically
* after scaling.
*/
@Test
public void testConfigureBounds_CENTER_CROP_V() {
Rect bounds = new Rect(10, 10, 410, 310);
int width = 200;
int height = 300;
Matrix expectedMatrix = new Matrix();
expectedMatrix.setScale(2.0f, 2.0f);
expectedMatrix.postTranslate(10, -139);
testConfigureBounds(bounds, width, height, ScaleType.CENTER_CROP, null, expectedMatrix);
}
/**
* Underlying drawable's aspect ratio is bigger than view's, so it has to be slided horizontally
* after scaling. Focus point is too much left, so it cannot be completely centered. Left-most
* part of the image is displayed.
*/
@Test
public void testConfigureBounds_FOCUS_CROP_HL() {
Rect bounds = new Rect(10, 10, 410, 310);
int width = 400;
int height = 200;
PointF focusPoint = new PointF(0.1f, 0.5f);
Matrix expectedMatrix = new Matrix();
expectedMatrix.setScale(1.5f, 1.5f);
expectedMatrix.postTranslate(10, 10);
testConfigureBounds(bounds, width, height, ScaleType.FOCUS_CROP, focusPoint, expectedMatrix);
}
/**
* Underlying drawable's aspect ratio is bigger than view's, so it has to be slided horizontally
* after scaling. Focus point is at 40% and it can be completely centered.
*/
@Test
public void testConfigureBounds_FOCUS_CROP_HC() {
Rect bounds = new Rect(10, 10, 410, 310);
int width = 400;
int height = 200;
PointF focusPoint = new PointF(0.40f, 0.5f);
Matrix expectedMatrix = new Matrix();
expectedMatrix.setScale(1.5f, 1.5f);
expectedMatrix.postTranslate(-29, 10);
testConfigureBounds(bounds, width, height, ScaleType.FOCUS_CROP, focusPoint, expectedMatrix);
}
/**
* Underlying drawable's aspect ratio is bigger than view's, so it has to be slided horizontally
* after scaling. Focus point is too much right, so it cannot be completely centered. Right-most
* part of the image is displayed.
*/
@Test
public void testConfigureBounds_FOCUS_CROP_HR() {
Rect bounds = new Rect(10, 10, 410, 310);
int width = 400;
int height = 200;
PointF focusPoint = new PointF(0.9f, 0.5f);
Matrix expectedMatrix = new Matrix();
expectedMatrix.setScale(1.5f, 1.5f);
expectedMatrix.postTranslate(-189, 10);
testConfigureBounds(bounds, width, height, ScaleType.FOCUS_CROP, focusPoint, expectedMatrix);
}
/**
* Underlying drawable's aspect ratio is smaller than view's, so it has to be slided vertically
* after scaling. Focus point is too much top, so it cannot be completely centered. Top-most
* part of the image is displayed.
*/
@Test
public void testConfigureBounds_FOCUS_CROP_VT() {
Rect bounds = new Rect(10, 10, 410, 310);
int width = 200;
int height = 300;
PointF focusPoint = new PointF(0.5f, 0.1f);
Matrix expectedMatrix = new Matrix();
expectedMatrix.setScale(2.0f, 2.0f);
expectedMatrix.postTranslate(10, 10);
testConfigureBounds(bounds, width, height, ScaleType.FOCUS_CROP, focusPoint, expectedMatrix);
}
/**
* Underlying drawable's aspect ratio is smaller than view's, so it has to be slided vertically
* after scaling. Focus point is at 40% and it can be completely centered.
*/
@Test
public void testConfigureBounds_FOCUS_CROP_VC() {
Rect bounds = new Rect(10, 10, 410, 310);
int width = 200;
int height = 300;
PointF focusPoint = new PointF(0.5f, 0.4f);
Matrix expectedMatrix = new Matrix();
expectedMatrix.setScale(2.0f, 2.0f);
expectedMatrix.postTranslate(10, -79);
testConfigureBounds(bounds, width, height, ScaleType.FOCUS_CROP, focusPoint, expectedMatrix);
// expected bounds of the actual image after the scaling has been performed (without cropping)
testActualImageBounds(new RectF(10f, -79f, 410f, 521f));
}
/**
* Underlying drawable's aspect ratio is smaller than view's, so it has to be slided vertically
* after scaling. Focus point is too much bottom, so it cannot be completely centered. Bottom-most
* part of the image is displayed.
*/
@Test
public void testConfigureBounds_FOCUS_CROP_VB() {
Rect bounds = new Rect(10, 10, 410, 310);
int width = 200;
int height = 300;
PointF focusPoint = new PointF(0.5f, 0.9f);
Matrix expectedMatrix = new Matrix();
expectedMatrix.setScale(2.0f, 2.0f);
expectedMatrix.postTranslate(10, -289);
testConfigureBounds(bounds, width, height, ScaleType.FOCUS_CROP, focusPoint, expectedMatrix);
}
private void testConfigureBounds(
Rect viewBounds,
int underlyingWidth,
int underlyingHeight,
ScaleType scaleType,
PointF focusPoint,
Matrix expectedMatrix) {
mScaleTypeDrawable.setScaleType(scaleType);
if (focusPoint != null) {
mScaleTypeDrawable.setFocusPoint(focusPoint);
}
mScaleTypeDrawable.setBounds(viewBounds);
reset(mUnderlyingDrawable);
when(mUnderlyingDrawable.getIntrinsicWidth()).thenReturn(underlyingWidth);
when(mUnderlyingDrawable.getIntrinsicHeight()).thenReturn(underlyingHeight);
mScaleTypeDrawable.configureBounds();
verify(mUnderlyingDrawable).getIntrinsicWidth();
verify(mUnderlyingDrawable).getIntrinsicHeight();
verify(mUnderlyingDrawable).setBounds(0, 0, underlyingWidth, underlyingHeight);
AndroidGraphicsTestUtils.assertEquals(expectedMatrix, mScaleTypeDrawable.mDrawMatrix);
verifyNoMoreInteractions(mUnderlyingDrawable);
}
private void testActualImageBounds(RectF expectedActualImageBounds) {
// TODO(5469563): enable this once we have a decent implementation of ShadowMatrix
//RectF actualImageBounds = new RectF();
//mScaleTypeDrawable.getTransformedBounds(actualImageBounds);
//Assert.assertEquals(expectedActualImageBounds, actualImageBounds);
}
}