Commit 9c0cae25 authored by ckitagawa's avatar ckitagawa Committed by Commit Bot

[Paint Preview] Create viewport class

This CL replaces the viewport state in PlayerFrameMediator with a new
PlayerFrameViewport class for managing state.

This causes a chain reaction requiring
1. A number of new method calls.
2. Removal of scale updates from moveViewport
3. Removal of scale maps for storing bitmaps

Bug: 1099722
Change-Id: Ia666485b59b0808af20055a1c023eb9e5176ecf5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2285257Reviewed-by: default avatarMehran Mahmoudi <mahmoudi@chromium.org>
Commit-Queue: Calder Kitagawa <ckitagawa@chromium.org>
Cr-Commit-Position: refs/heads/master@{#786428}
parent 5393a7e9
...@@ -62,6 +62,7 @@ android_library("java") { ...@@ -62,6 +62,7 @@ android_library("java") {
"java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameView.java", "java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameView.java",
"java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameViewBinder.java", "java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameViewBinder.java",
"java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameViewDelegate.java", "java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameViewDelegate.java",
"java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameViewport.java",
] ]
deps = [ deps = [
......
...@@ -8,6 +8,7 @@ import android.graphics.Bitmap; ...@@ -8,6 +8,7 @@ import android.graphics.Bitmap;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Handler; import android.os.Handler;
import android.util.Size;
import android.view.View; import android.view.View;
import android.widget.OverScroller; import android.widget.OverScroller;
...@@ -20,9 +21,7 @@ import org.chromium.components.paintpreview.player.PlayerCompositorDelegate; ...@@ -20,9 +21,7 @@ import org.chromium.components.paintpreview.player.PlayerCompositorDelegate;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Handles the business logic for the player frame component. Concretely, this class is responsible * Handles the business logic for the player frame component. Concretely, this class is responsible
...@@ -43,10 +42,8 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -43,10 +42,8 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
/** The GUID associated with the frame that this class is representing. */ /** The GUID associated with the frame that this class is representing. */
private final UnguessableToken mGuid; private final UnguessableToken mGuid;
/** The content width inside this frame, at a scale factor of 1. */ /** The size of the content inside this frame, at a scale factor of 1. */
private final int mContentWidth; private final Size mContentSize;
/** The content height inside this frame, at a scale factor of 1. */
private final int mContentHeight;
/** /**
* Contains all {@link View}s corresponding to this frame's sub-frames. * Contains all {@link View}s corresponding to this frame's sub-frames.
*/ */
...@@ -68,32 +65,26 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -68,32 +65,26 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
private final PlayerCompositorDelegate mCompositorDelegate; private final PlayerCompositorDelegate mCompositorDelegate;
private final OverScroller mScroller; private final OverScroller mScroller;
private final Handler mScrollerHandler; private final Handler mScrollerHandler;
/** The user-visible area for this frame. */ /** The viewport of this frame. */
private final Rect mViewportRect = new Rect(); @VisibleForTesting
/** Rect used for requesting a new bitmap from Paint Preview compositor. */ final PlayerFrameViewport mViewport = new PlayerFrameViewport(new Size(0, 0), new Matrix());
private final Rect mBitmapRequestRect = new Rect(); /** Dimension of tiles. */
/** Dimension of tiles for each scale factor. */ private int[] mTileDimensions;
private final Map<Float, int[]> mTileDimensions = new HashMap<>(); /** Bitmaps that make up the content of this frame. */
/** private Bitmap[][] mBitmapMatrix;
* A scale factor cache of matrices of bitmaps that make up the content of this frame at a /** Whether a request for a bitmap tile is pending. */
* given scale factor. private boolean[][] mPendingBitmapRequests;
*/
private final Map<Float, Bitmap[][]> mBitmapMatrix = new HashMap<>();
/** Whether a request for a bitmap tile is pending, mapped by scale factor. */
private final Map<Float, boolean[][]> mPendingBitmapRequests = new HashMap<>();
/** /**
* Whether we currently need a bitmap tile. This is used for deleting bitmaps that we don't * Whether we currently need a bitmap tile. This is used for deleting bitmaps that we don't
* need and freeing up memory. * need and freeing up memory.
*/ */
@VisibleForTesting @VisibleForTesting
final Map<Float, boolean[][]> mRequiredBitmaps = new HashMap<>(); boolean[][] mRequiredBitmaps;
/** The current scale factor. */
private float mScaleFactor; /** Handles scaling of bitmaps. */
private final Matrix mBitmapScaleMatrix = new Matrix();
private float mInitialScaleFactor; private float mInitialScaleFactor;
private float mUncommittedScaleFactor = 0f; private float mUncommittedScaleFactor = 0f;
@VisibleForTesting
final Matrix mViewportScaleMatrix = new Matrix();
private final Matrix mBitmapScaleMatrix = new Matrix();
/** For swipe-to-refresh logic */ /** For swipe-to-refresh logic */
private OverscrollHandler mOverscrollHandler; private OverscrollHandler mOverscrollHandler;
...@@ -109,11 +100,10 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -109,11 +100,10 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
mCompositorDelegate = compositorDelegate; mCompositorDelegate = compositorDelegate;
mScroller = scroller; mScroller = scroller;
mGuid = frameGuid; mGuid = frameGuid;
mContentWidth = contentWidth; mContentSize = new Size(contentWidth, contentHeight);
mContentHeight = contentHeight;
mScrollerHandler = new Handler(); mScrollerHandler = new Handler();
mViewportRect.offset(initialScrollX, initialScrollY); mViewport.offset(initialScrollX, initialScrollY);
mViewportScaleMatrix.postTranslate(-initialScrollX, -initialScrollY); mViewport.setScale(0f);
} }
/** /**
...@@ -135,21 +125,20 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -135,21 +125,20 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
public void setLayoutDimensions(int width, int height) { public void setLayoutDimensions(int width, int height) {
// Don't trigger a re-draw if we are actively scaling. // Don't trigger a re-draw if we are actively scaling.
if (!mBitmapScaleMatrix.isIdentity()) { if (!mBitmapScaleMatrix.isIdentity()) {
mViewportRect.set(mViewportRect.left, mViewportRect.top, mViewportRect.left + width, mViewport.setSize(width, height);
mViewportRect.top + height);
return; return;
} }
// Set initial scale so that content width fits within the layout dimensions. // Set initial scale so that content width fits within the layout dimensions.
mInitialScaleFactor = ((float) width) / ((float) mContentWidth); mInitialScaleFactor = ((float) width) / ((float) mContentSize.getWidth());
updateViewportSize( final float scaleFactor = mViewport.getScale();
width, height, (mScaleFactor == 0f) ? mInitialScaleFactor : mScaleFactor); updateViewportSize(width, height, (scaleFactor == 0f) ? mInitialScaleFactor : scaleFactor);
} }
public void setBitmapScaleMatrix(Matrix matrix, float scaleFactor) { public void setBitmapScaleMatrix(Matrix matrix, float scaleFactor) {
// Don't update the subframes if the matrix is identity as it will be forcibly recalculated. // Don't update the subframes if the matrix is identity as it will be forcibly recalculated.
if (!matrix.isIdentity()) { if (!matrix.isIdentity()) {
updateSubFrames(mViewportRect, scaleFactor); updateSubFrames(mViewport.asRect(), scaleFactor);
} }
setBitmapScaleMatrixInternal(matrix, scaleFactor); setBitmapScaleMatrixInternal(matrix, scaleFactor);
} }
...@@ -160,7 +149,7 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -160,7 +149,7 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
@VisibleForTesting @VisibleForTesting
void resetScaleFactor() { void resetScaleFactor() {
// Set scale factor to 0 so subframes get the correct scale factor on scale completion. // Set scale factor to 0 so subframes get the correct scale factor on scale completion.
mScaleFactor = 0; mViewport.setScale(0f);
for (int i = 0; i < mSubFrameViews.size(); i++) { for (int i = 0; i < mSubFrameViews.size(); i++) {
mSubFrameMediators.get(i).resetScaleFactor(); mSubFrameMediators.get(i).resetScaleFactor();
} }
...@@ -183,8 +172,10 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -183,8 +172,10 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
@VisibleForTesting @VisibleForTesting
void forceRedraw() { void forceRedraw() {
mInitialScaleFactor = ((float) mViewportRect.width()) / ((float) mContentWidth); mInitialScaleFactor = ((float) mViewport.getWidth()) / ((float) mContentSize.getWidth());
moveViewport(0, 0, (mScaleFactor == 0f) ? mInitialScaleFactor : mScaleFactor); final float scaleFactor = mViewport.getScale();
mViewport.setScale((scaleFactor == 0f) ? mInitialScaleFactor : scaleFactor);
moveViewport(0, 0, true);
for (int i = 0; i < mSubFrameViews.size(); i++) { for (int i = 0; i < mSubFrameViews.size(); i++) {
if (mSubFrameViews.get(i).getVisibility() != View.VISIBLE) continue; if (mSubFrameViews.get(i).getVisibility() != View.VISIBLE) continue;
...@@ -196,68 +187,65 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -196,68 +187,65 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
if (width <= 0 || height <= 0) return; if (width <= 0 || height <= 0) return;
// Ensure the viewport is within the bounds of the content. // Ensure the viewport is within the bounds of the content.
final int left = Math.max( final int left = Math.max(0,
0, Math.min(mViewportRect.left, Math.round(mContentWidth * scaleFactor) - width)); Math.min(Math.round(mViewport.getTransX()),
final int top = Math.max( Math.round(mContentSize.getWidth() * scaleFactor) - width));
0, Math.min(mViewportRect.top, Math.round(mContentHeight * scaleFactor) - height)); final int top = Math.max(0,
mViewportRect.set(left, top, left + width, top + height); Math.min(Math.round(mViewport.getTransY()),
moveViewport(0, 0, scaleFactor); Math.round(mContentSize.getHeight() * scaleFactor) - height));
mViewport.setTrans(left, top);
mViewport.setSize(width, height);
final float oldScaleFactor = mViewport.getScale();
mViewport.setScale(scaleFactor);
moveViewport(0, 0, oldScaleFactor != scaleFactor);
} }
/** /**
* Called when the view port is moved or the scale factor is changed. Updates the view port * Called when the view port is moved or the scale factor is changed. Updates the view port
* and requests bitmap tiles for portion of the view port that don't have bitmap tiles. * and requests bitmap tiles for portion of the view port that don't have bitmap tiles.
* @param distanceX The horizontal distance that the view port should be moved by. * @param distanceX The horizontal distance that the view port should be moved by.
* @param distanceY The vertical distance that the view port should be moved by. * @param distanceY The vertical distance that the view port should be moved by.
* @param scaleFactor The new scale factor. * @param scaleUpdated Whether the scale was updated.
*/ */
private void moveViewport(int distanceX, int distanceY, float scaleFactor) { private void moveViewport(int distanceX, int distanceY, boolean scaleUpdated) {
// Initialize the bitmap matrix for this scale factor if we haven't already. final float scaleFactor = mViewport.getScale();
int[] tileDimensions = mTileDimensions.get(scaleFactor); if (scaleUpdated || mBitmapMatrix == null) {
Bitmap[][] bitmapMatrix = mBitmapMatrix.get(scaleFactor);
boolean[][] pendingBitmapRequests = mPendingBitmapRequests.get(scaleFactor);
boolean[][] requiredBitmaps = mRequiredBitmaps.get(scaleFactor);
if (bitmapMatrix == null) {
// Each tile is as big as the initial view port. Here we determine the number of // Each tile is as big as the initial view port. Here we determine the number of
// columns and rows for the current scale factor. // columns and rows for the current scale factor.
int rows = (int) Math.ceil((mContentHeight * scaleFactor) / mViewportRect.height()); int rows = (int) Math.ceil(
int cols = (int) Math.ceil((mContentWidth * scaleFactor) / mViewportRect.width()); (mContentSize.getHeight() * scaleFactor) / mViewport.getHeight());
tileDimensions = new int[] {mViewportRect.width(), mViewportRect.height()}; int cols =
bitmapMatrix = new Bitmap[rows][cols]; (int) Math.ceil((mContentSize.getWidth() * scaleFactor) / mViewport.getWidth());
pendingBitmapRequests = new boolean[rows][cols]; mTileDimensions = new int[] {mViewport.getWidth(), mViewport.getHeight()};
requiredBitmaps = new boolean[rows][cols]; mBitmapMatrix = new Bitmap[rows][cols];
mTileDimensions.put(scaleFactor, tileDimensions); mPendingBitmapRequests = new boolean[rows][cols];
mBitmapMatrix.put(scaleFactor, bitmapMatrix); mRequiredBitmaps = new boolean[rows][cols];
mPendingBitmapRequests.put(scaleFactor, pendingBitmapRequests);
mRequiredBitmaps.put(scaleFactor, requiredBitmaps);
} }
// Update mViewportRect and let the view know. PropertyModelChangeProcessor is smart about // Update mViewport and let the view know. PropertyModelChangeProcessor is smart about
// this and will only update the view if mViewportRect is actually changed. // this and will only update the view if mViewport's rect is actually changed.
mViewportRect.offset(distanceX, distanceY); mViewport.offset(distanceX, distanceY);
// Keep translations up to date for the viewport matrix so that future scale operations are Rect viewportRect = mViewport.asRect();
// correct. updateSubFrames(viewportRect, mViewport.getScale());
mViewportScaleMatrix.postTranslate(-distanceX, -distanceY); mModel.set(PlayerFrameProperties.TILE_DIMENSIONS, mTileDimensions);
updateSubFrames(mViewportRect, scaleFactor); mModel.set(PlayerFrameProperties.VIEWPORT, mViewport.asRect());
mModel.set(PlayerFrameProperties.TILE_DIMENSIONS, tileDimensions);
mModel.set(PlayerFrameProperties.VIEWPORT, mViewportRect);
// Clear the required bitmaps matrix. It will be updated in #requestBitmapForTile. // Clear the required bitmaps matrix. It will be updated in #requestBitmapForTile.
for (int row = 0; row < requiredBitmaps.length; row++) { for (int row = 0; row < mRequiredBitmaps.length; row++) {
for (int col = 0; col < requiredBitmaps[row].length; col++) { for (int col = 0; col < mRequiredBitmaps[row].length; col++) {
requiredBitmaps[row][col] = false; mRequiredBitmaps[row][col] = false;
} }
} }
// Request bitmaps for tiles inside the view port that don't already have a bitmap. // Request bitmaps for tiles inside the view port that don't already have a bitmap.
final int tileWidth = tileDimensions[0]; final int tileWidth = mTileDimensions[0];
final int tileHeight = tileDimensions[1]; final int tileHeight = mTileDimensions[1];
final int colStart = Math.max(0, (int) Math.floor((double) mViewportRect.left / tileWidth)); final int colStart = Math.max(0, (int) Math.floor((double) viewportRect.left / tileWidth));
final int colEnd = Math.min(requiredBitmaps[0].length, final int colEnd = Math.min(mRequiredBitmaps[0].length,
(int) Math.ceil((double) mViewportRect.right / tileWidth)); (int) Math.ceil((double) viewportRect.right / tileWidth));
final int rowStart = Math.max(0, (int) Math.floor((double) mViewportRect.top / tileHeight)); final int rowStart = Math.max(0, (int) Math.floor((double) viewportRect.top / tileHeight));
final int rowEnd = Math.min(requiredBitmaps.length, final int rowEnd = Math.min(mRequiredBitmaps.length,
(int) Math.ceil((double) mViewportRect.bottom / tileHeight)); (int) Math.ceil((double) viewportRect.bottom / tileHeight));
for (int col = colStart; col < colEnd; col++) { for (int col = colStart; col < colEnd; col++) {
for (int row = rowStart; row < rowEnd; row++) { for (int row = rowStart; row < rowEnd; row++) {
int tileLeft = col * tileWidth; int tileLeft = col * tileWidth;
...@@ -279,11 +267,8 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -279,11 +267,8 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
// If the scale factor is changed, the view should get the correct bitmap matrix. // If the scale factor is changed, the view should get the correct bitmap matrix.
// TODO(crbug/1090804): "Double buffer" this such that there is no period where there is a // TODO(crbug/1090804): "Double buffer" this such that there is no period where there is a
// blank screen between scale finishing and new bitmaps being fetched. // blank screen between scale finishing and new bitmaps being fetched.
if (scaleFactor != mScaleFactor) { if (scaleUpdated) {
mModel.set(PlayerFrameProperties.BITMAP_MATRIX, mBitmapMatrix.get(scaleFactor)); mModel.set(PlayerFrameProperties.BITMAP_MATRIX, mBitmapMatrix);
mBitmapMatrix.remove(mScaleFactor); // Eagerly free to avoid OOM.
mRequiredBitmaps.remove(mScaleFactor);
mScaleFactor = scaleFactor;
} }
} }
...@@ -316,14 +301,13 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -316,14 +301,13 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
private void requestBitmapForAdjacentTiles( private void requestBitmapForAdjacentTiles(
int tileWidth, int tileHeight, int row, int col, float scaleFactor) { int tileWidth, int tileHeight, int row, int col, float scaleFactor) {
Bitmap[][] bitmapMatrix = mBitmapMatrix.get(scaleFactor); if (mBitmapMatrix == null) return;
if (bitmapMatrix == null) return;
if (row > 0) { if (row > 0) {
requestBitmapForTile(col * tileWidth, (row - 1) * tileHeight, tileWidth, tileHeight, requestBitmapForTile(col * tileWidth, (row - 1) * tileHeight, tileWidth, tileHeight,
row - 1, col, scaleFactor); row - 1, col, scaleFactor);
} }
if (row < bitmapMatrix.length - 1) { if (row < mBitmapMatrix.length - 1) {
requestBitmapForTile(col * tileWidth, (row + 1) * tileHeight, tileWidth, tileHeight, requestBitmapForTile(col * tileWidth, (row + 1) * tileHeight, tileWidth, tileHeight,
row + 1, col, scaleFactor); row + 1, col, scaleFactor);
} }
...@@ -331,7 +315,7 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -331,7 +315,7 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
requestBitmapForTile((col - 1) * tileWidth, row * tileHeight, tileWidth, tileHeight, requestBitmapForTile((col - 1) * tileWidth, row * tileHeight, tileWidth, tileHeight,
row, col - 1, scaleFactor); row, col - 1, scaleFactor);
} }
if (col < bitmapMatrix[row].length - 1) { if (col < mBitmapMatrix[row].length - 1) {
requestBitmapForTile((col + 1) * tileWidth, row * tileHeight, tileWidth, tileHeight, requestBitmapForTile((col + 1) * tileWidth, row * tileHeight, tileWidth, tileHeight,
row, col + 1, scaleFactor); row, col + 1, scaleFactor);
} }
...@@ -339,39 +323,31 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -339,39 +323,31 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
private void requestBitmapForTile( private void requestBitmapForTile(
int x, int y, int width, int height, int row, int col, float scaleFactor) { int x, int y, int width, int height, int row, int col, float scaleFactor) {
Bitmap[][] bitmapMatrix = mBitmapMatrix.get(scaleFactor); if (mRequiredBitmaps == null) return;
boolean[][] pendingBitmapRequests = mPendingBitmapRequests.get(scaleFactor);
boolean[][] requiredBitmaps = mRequiredBitmaps.get(scaleFactor); mRequiredBitmaps[row][col] = true;
if (requiredBitmaps == null) return; if (mBitmapMatrix == null || mPendingBitmapRequests == null
|| mBitmapMatrix[row][col] != null || mPendingBitmapRequests[row][col]) {
requiredBitmaps[row][col] = true;
if (bitmapMatrix == null || pendingBitmapRequests == null || bitmapMatrix[row][col] != null
|| pendingBitmapRequests[row][col]) {
return; return;
} }
mBitmapRequestRect.set(x, y, x + width, y + height);
BitmapRequestHandler bitmapRequestHandler = new BitmapRequestHandler(row, col, scaleFactor); BitmapRequestHandler bitmapRequestHandler = new BitmapRequestHandler(row, col, scaleFactor);
pendingBitmapRequests[row][col] = true; mPendingBitmapRequests[row][col] = true;
mCompositorDelegate.requestBitmap( mCompositorDelegate.requestBitmap(mGuid, new Rect(x, y, x + width, y + height), scaleFactor,
mGuid, mBitmapRequestRect, scaleFactor, bitmapRequestHandler, bitmapRequestHandler); bitmapRequestHandler, bitmapRequestHandler);
} }
/** /**
* Remove previously fetched bitmaps that are no longer required according to * Remove previously fetched bitmaps that are no longer required according to
* {@link #mRequiredBitmaps}. * {@link #mRequiredBitmaps}.
*/ */
private void deleteUnrequiredBitmaps(float scaleFactor) { private void deleteUnrequiredBitmaps() {
Bitmap[][] bitmapMatrix = mBitmapMatrix.get(scaleFactor); for (int row = 0; row < mBitmapMatrix.length; row++) {
boolean[][] requiredBitmaps = mRequiredBitmaps.get(scaleFactor); for (int col = 0; col < mBitmapMatrix[row].length; col++) {
if (bitmapMatrix == null || requiredBitmaps == null) return; Bitmap bitmap = mBitmapMatrix[row][col];
if (!mRequiredBitmaps[row][col] && bitmap != null) {
for (int row = 0; row < bitmapMatrix.length; row++) {
for (int col = 0; col < bitmapMatrix[row].length; col++) {
Bitmap bitmap = bitmapMatrix[row][col];
if (!requiredBitmaps[row][col] && bitmap != null) {
bitmap.recycle(); bitmap.recycle();
bitmapMatrix[row][col] = null; mBitmapMatrix[row][col] = null;
} }
} }
} }
...@@ -401,7 +377,7 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -401,7 +377,7 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
} }
private boolean maybeHandleOverscroll(float distanceY) { private boolean maybeHandleOverscroll(float distanceY) {
if (mOverscrollHandler == null || mViewportRect.top != 0) return false; if (mOverscrollHandler == null || mViewport.getTransY() != 0f) return false;
// Ignore if there is no active overscroll and the direction is down. // Ignore if there is no active overscroll and the direction is down.
if (!mIsOverscrolling && distanceY <= 0) return false; if (!mIsOverscrolling && distanceY <= 0) return false;
...@@ -431,25 +407,27 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -431,25 +407,27 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
int validDistanceX = 0; int validDistanceX = 0;
int validDistanceY = 0; int validDistanceY = 0;
float scaledContentWidth = mContentWidth * mScaleFactor; final float scaleFactor = mViewport.getScale();
float scaledContentHeight = mContentHeight * mScaleFactor; float scaledContentWidth = mContentSize.getWidth() * scaleFactor;
float scaledContentHeight = mContentSize.getHeight() * scaleFactor;
if (mViewportRect.left > 0 && distanceX < 0) {
validDistanceX = (int) Math.max(distanceX, -1f * mViewportRect.left); Rect viewportRect = mViewport.asRect();
} else if (mViewportRect.right < scaledContentWidth && distanceX > 0) { if (viewportRect.left > 0 && distanceX < 0) {
validDistanceX = (int) Math.min(distanceX, scaledContentWidth - mViewportRect.right); validDistanceX = (int) Math.max(distanceX, -1f * viewportRect.left);
} else if (viewportRect.right < scaledContentWidth && distanceX > 0) {
validDistanceX = (int) Math.min(distanceX, scaledContentWidth - viewportRect.right);
} }
if (mViewportRect.top > 0 && distanceY < 0) { if (viewportRect.top > 0 && distanceY < 0) {
validDistanceY = (int) Math.max(distanceY, -1f * mViewportRect.top); validDistanceY = (int) Math.max(distanceY, -1f * viewportRect.top);
} else if (mViewportRect.bottom < scaledContentHeight && distanceY > 0) { } else if (viewportRect.bottom < scaledContentHeight && distanceY > 0) {
validDistanceY = (int) Math.min(distanceY, scaledContentHeight - mViewportRect.bottom); validDistanceY = (int) Math.min(distanceY, scaledContentHeight - viewportRect.bottom);
} }
if (validDistanceX == 0 && validDistanceY == 0) { if (validDistanceX == 0 && validDistanceY == 0) {
return false; return false;
} }
moveViewport(validDistanceX, validDistanceY, mScaleFactor); moveViewport(validDistanceX, validDistanceY, false);
return true; return true;
} }
...@@ -463,35 +441,31 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -463,35 +441,31 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
* During {@link #scaleBy()} the gesture is still ongoing. * During {@link #scaleBy()} the gesture is still ongoing.
* *
* On each scale gesture the |scaleFactor| is applied to |mUncommittedScaleFactor| which * On each scale gesture the |scaleFactor| is applied to |mUncommittedScaleFactor| which
* accumulates the scale starting from the currently committed |mScaleFactor|. This is * accumulates the scale starting from the currently committed scale factor. This is
* committed when {@link #scaleFinished()} event occurs. This is for the viewport reference * committed when {@link #scaleFinished()} event occurs. This is for the viewport reference
* frame. |mViewportScaleMatrix| also accumulates the transforms to track the translation * frame. |mViewport| also accumulates the transforms to track the translation behavior.
* behavior.
* *
* |mBitmapScaleMatrix| tracks scaling from the perspective of the bitmaps. This is used to * |mBitmapScaleMatrix| tracks scaling from the perspective of the bitmaps. This is used to
* transform the canvas the bitmaps are painted on such that scaled images can be shown * transform the canvas the bitmaps are painted on such that scaled images can be shown
* mid-gesture. * mid-gesture.
* *
* Each subframe is updated with a new rect based on the interim scale factor and when the * Each subframe is updated with a new rect based on the interim scale factor and when the
* matrix is set in {@link PlayerFrameView#updateMatrix} the subframe matricies are recursively * matrix is set in {@link #setBitmapScaleMatrix()} the subframe matricies are recursively
* updated. * updated.
* *
* On {@link #scaleFinished()} the gesture is now considered finished. * On {@link #scaleFinished()} the gesture is now considered finished.
* *
* The values of |mViewportScaleMatrix| are extracted to get the final translation applied to * The final translation is applied to the viewport. The transform for the bitmaps (that is
* the viewport. The transform for the bitmaps (that is |mBitmapScaleMatrix|) is cancelled. * |mBitmapScaleMatrix|) is cancelled.
* *
* During {@link #moveViewport()} new bitmaps are requested for the main frame and subframes * During {@link #moveViewport()} new bitmaps are requested for the main frame and subframes
* to improve quality. * to improve quality.
*
* NOTE: |mViewportScaleMatrix| also need to consume scroll events in order to keep track of
* the correct translation.
*/ */
@Override @Override
public boolean scaleBy(float scaleFactor, float focalPointX, float focalPointY) { public boolean scaleBy(float scaleFactor, float focalPointX, float focalPointY) {
// This is filtered to only apply to the top level view upstream. // This is filtered to only apply to the top level view upstream.
if (mUncommittedScaleFactor == 0f) { if (mUncommittedScaleFactor == 0f) {
mUncommittedScaleFactor = mScaleFactor; mUncommittedScaleFactor = mViewport.getScale();
} }
mUncommittedScaleFactor *= scaleFactor; mUncommittedScaleFactor *= scaleFactor;
...@@ -502,43 +476,39 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -502,43 +476,39 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
// TODO(crbug/1090804): trigger a fetch of new bitmaps periodically when zooming out. // TODO(crbug/1090804): trigger a fetch of new bitmaps periodically when zooming out.
mViewportScaleMatrix.postScale(scaleFactor, scaleFactor, focalPointX, focalPointY); mViewport.scale(scaleFactor, focalPointX, focalPointY);
mBitmapScaleMatrix.postScale(scaleFactor, scaleFactor, focalPointX, focalPointY); mBitmapScaleMatrix.postScale(scaleFactor, scaleFactor, focalPointX, focalPointY);
float[] viewportScaleMatrixValues = new float[9];
mViewportScaleMatrix.getValues(viewportScaleMatrixValues);
float[] bitmapScaleMatrixValues = new float[9]; float[] bitmapScaleMatrixValues = new float[9];
mBitmapScaleMatrix.getValues(bitmapScaleMatrixValues); mBitmapScaleMatrix.getValues(bitmapScaleMatrixValues);
// It is possible the scale pushed the viewport outside the content bounds. These new values // It is possible the scale pushed the viewport outside the content bounds. These new values
// are forced to be within bounds. // are forced to be within bounds.
final float newX = -1f Rect uncorrectedViewportRect = mViewport.asRect();
* Math.max(0f, final float correctedX = Math.max(0f,
Math.min(-viewportScaleMatrixValues[Matrix.MTRANS_X], Math.min(uncorrectedViewportRect.left,
mContentWidth * mUncommittedScaleFactor - mViewportRect.width())); mContentSize.getWidth() * mUncommittedScaleFactor - mViewport.getWidth()));
final float newY = -1f final float correctedY = Math.max(0f,
* Math.max(0f, Math.min(uncorrectedViewportRect.top,
Math.min(-viewportScaleMatrixValues[Matrix.MTRANS_Y], mContentSize.getHeight() * mUncommittedScaleFactor
mContentHeight * mUncommittedScaleFactor - mViewportRect.height())); - mViewport.getHeight()));
final int newXRounded = Math.abs(Math.round(newX)); final int correctedXRounded = Math.abs(Math.round(correctedX));
final int newYRounded = Math.abs(Math.round(newY)); final int correctedYRounded = Math.abs(Math.round(correctedY));
updateSubFrames(new Rect(newXRounded, newYRounded, newXRounded + mViewportRect.width(), updateSubFrames(new Rect(correctedXRounded, correctedYRounded,
newYRounded + mViewportRect.height()), correctedXRounded + mViewport.getWidth(),
correctedYRounded + mViewport.getHeight()),
mUncommittedScaleFactor); mUncommittedScaleFactor);
if (newX != viewportScaleMatrixValues[Matrix.MTRANS_X] if (correctedX != uncorrectedViewportRect.left
|| newY != viewportScaleMatrixValues[Matrix.MTRANS_Y]) { || correctedY != uncorrectedViewportRect.top) {
// This is the delta required to force the viewport to be inside the bounds of the // This is the delta required to force the viewport to be inside the bounds of the
// content. // content.
final float deltaX = newX - viewportScaleMatrixValues[Matrix.MTRANS_X]; final float deltaX = uncorrectedViewportRect.left - correctedX;
final float deltaY = newY - viewportScaleMatrixValues[Matrix.MTRANS_Y]; final float deltaY = uncorrectedViewportRect.top - correctedY;
// Directly used the forced bounds of the viewport reference frame for the viewport // Directly used the forced bounds of the viewport reference frame for the viewport
// scale matrix. // scale matrix.
viewportScaleMatrixValues[Matrix.MTRANS_X] = newX; mViewport.setTrans(correctedX, correctedY);
viewportScaleMatrixValues[Matrix.MTRANS_Y] = newY;
mViewportScaleMatrix.setValues(viewportScaleMatrixValues);
// For the bitmap matrix we only want the delta as its position will be different as the // For the bitmap matrix we only want the delta as its position will be different as the
// coordinates are bitmap relative. // coordinates are bitmap relative.
...@@ -562,28 +532,19 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -562,28 +532,19 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
Math.max(mInitialScaleFactor, Math.min(mUncommittedScaleFactor, MAX_SCALE_FACTOR)); Math.max(mInitialScaleFactor, Math.min(mUncommittedScaleFactor, MAX_SCALE_FACTOR));
mUncommittedScaleFactor = 0f; mUncommittedScaleFactor = 0f;
float[] matrixValues = new float[9]; final float correctedX = Math.max(0f,
mViewportScaleMatrix.getValues(matrixValues); Math.min(mViewport.getTransX(),
final float newX = Math.max(0f, mContentSize.getWidth() * finalScaleFactor - mViewport.getWidth()));
Math.min(-matrixValues[Matrix.MTRANS_X], final float correctedY = Math.max(0f,
mContentWidth * finalScaleFactor - mViewportRect.width())); Math.min(mViewport.getTransY(),
final float newY = Math.max(0f, mContentSize.getHeight() * finalScaleFactor - mViewport.getHeight()));
Math.min(-matrixValues[Matrix.MTRANS_Y], mViewport.setTrans(correctedX, correctedY);
mContentHeight * finalScaleFactor - mViewportRect.height())); mViewport.setScale(finalScaleFactor);
matrixValues[Matrix.MTRANS_X] = -newX;
matrixValues[Matrix.MTRANS_Y] = -newY;
matrixValues[Matrix.MSCALE_X] = finalScaleFactor;
matrixValues[Matrix.MSCALE_Y] = finalScaleFactor;
mViewportScaleMatrix.setValues(matrixValues);
final int newXRounded = Math.round(newX);
final int newYRounded = Math.round(newY);
mViewportRect.set(newXRounded, newYRounded, newXRounded + mViewportRect.width(),
newYRounded + mViewportRect.height());
for (int i = 0; i < mSubFrameViews.size(); i++) { for (int i = 0; i < mSubFrameViews.size(); i++) {
mSubFrameMediators.get(i).resetScaleFactor(); mSubFrameMediators.get(i).resetScaleFactor();
} }
moveViewport(0, 0, finalScaleFactor); moveViewport(0, 0, true);
for (int i = 0; i < mSubFrameViews.size(); i++) { for (int i = 0; i < mSubFrameViews.size(); i++) {
if (mSubFrameViews.get(i).getVisibility() != View.VISIBLE) continue; if (mSubFrameViews.get(i).getVisibility() != View.VISIBLE) continue;
...@@ -597,19 +558,22 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -597,19 +558,22 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
public void onClick(int x, int y) { public void onClick(int x, int y) {
// x and y are in the View's coordinate system (scaled). This needs to be adjusted to the // x and y are in the View's coordinate system (scaled). This needs to be adjusted to the
// absolute coordinate system for hit testing. // absolute coordinate system for hit testing.
final float scaleFactor = mViewport.getScale();
mCompositorDelegate.onClick(mGuid, mCompositorDelegate.onClick(mGuid,
Math.round((float) (mViewportRect.left + x) / mScaleFactor), Math.round((float) (mViewport.getTransX() + x) / scaleFactor),
Math.round((float) (mViewportRect.top + y) / mScaleFactor)); Math.round((float) (mViewport.getTransY() + y) / scaleFactor));
} }
@Override @Override
public boolean onFling(float velocityX, float velocityY) { public boolean onFling(float velocityX, float velocityY) {
int scaledContentWidth = (int) (mContentWidth * mScaleFactor); final float scaleFactor = mViewport.getScale();
int scaledContentHeight = (int) (mContentHeight * mScaleFactor); int scaledContentWidth = (int) (mContentSize.getWidth() * scaleFactor);
int scaledContentHeight = (int) (mContentSize.getHeight() * scaleFactor);
mScroller.forceFinished(true); mScroller.forceFinished(true);
mScroller.fling(mViewportRect.left, mViewportRect.top, (int) -velocityX, (int) -velocityY, Rect viewportRect = mViewport.asRect();
0, scaledContentWidth - mViewportRect.width(), 0, mScroller.fling(viewportRect.left, viewportRect.top, (int) -velocityX, (int) -velocityY, 0,
scaledContentHeight - mViewportRect.height()); scaledContentWidth - viewportRect.width(), 0,
scaledContentHeight - viewportRect.height());
mScrollerHandler.post(this::handleFling); mScrollerHandler.post(this::handleFling);
return true; return true;
...@@ -626,8 +590,8 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -626,8 +590,8 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
if (mScroller.isFinished()) return; if (mScroller.isFinished()) return;
boolean shouldContinue = mScroller.computeScrollOffset(); boolean shouldContinue = mScroller.computeScrollOffset();
int deltaX = mScroller.getCurrX() - mViewportRect.left; int deltaX = mScroller.getCurrX() - Math.round(mViewport.getTransX());
int deltaY = mScroller.getCurrY() - mViewportRect.top; int deltaY = mScroller.getCurrY() - Math.round(mViewport.getTransY());
scrollByInternal(deltaX, deltaY); scrollByInternal(deltaX, deltaY);
if (shouldContinue) { if (shouldContinue) {
...@@ -659,26 +623,18 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -659,26 +623,18 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
run(); run();
return; return;
} }
Bitmap[][] bitmapMatrix = mBitmapMatrix.get(mRequestScaleFactor); if (mViewport.getScale() != mRequestScaleFactor
boolean[][] requiredBitmaps = mRequiredBitmaps.get(mRequestScaleFactor); || !mPendingBitmapRequests[mRequestRow][mRequestCol]
if (bitmapMatrix == null || requiredBitmaps == null) { || !mRequiredBitmaps[mRequestRow][mRequestCol]) {
result.recycle(); result.recycle();
deleteUnrequiredBitmaps();
return; return;
} }
assert mBitmapMatrix.get(mRequestScaleFactor)[mRequestRow][mRequestCol] == null; mPendingBitmapRequests[mRequestRow][mRequestCol] = false;
assert mPendingBitmapRequests.get(mRequestScaleFactor)[mRequestRow][mRequestCol]; mBitmapMatrix[mRequestRow][mRequestCol] = result;
mModel.set(PlayerFrameProperties.BITMAP_MATRIX, mBitmapMatrix);
mPendingBitmapRequests.get(mScaleFactor)[mRequestRow][mRequestCol] = false; deleteUnrequiredBitmaps();
if (requiredBitmaps[mRequestRow][mRequestCol]) {
bitmapMatrix[mRequestRow][mRequestCol] = result;
if (PlayerFrameMediator.this.mScaleFactor == mRequestScaleFactor) {
mModel.set(PlayerFrameProperties.BITMAP_MATRIX, bitmapMatrix);
}
} else {
result.recycle();
}
deleteUnrequiredBitmaps(mRequestScaleFactor);
} }
/** /**
...@@ -686,12 +642,14 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate { ...@@ -686,12 +642,14 @@ class PlayerFrameMediator implements PlayerFrameViewDelegate {
*/ */
@Override @Override
public void run() { public void run() {
if (mViewport.getScale() != mRequestScaleFactor) return;
// TODO(crbug.com/1021590): Handle errors. // TODO(crbug.com/1021590): Handle errors.
assert mBitmapMatrix.get(mRequestScaleFactor) != null; assert mBitmapMatrix != null;
assert mBitmapMatrix.get(mRequestScaleFactor)[mRequestRow][mRequestCol] == null; assert mBitmapMatrix[mRequestRow][mRequestCol] == null;
assert mPendingBitmapRequests.get(mRequestScaleFactor)[mRequestRow][mRequestCol]; assert mPendingBitmapRequests[mRequestRow][mRequestCol];
mPendingBitmapRequests.get(mScaleFactor)[mRequestRow][mRequestCol] = false; mPendingBitmapRequests[mRequestRow][mRequestCol] = false;
} }
} }
} }
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.components.paintpreview.player.frame;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.util.Size;
import androidx.annotation.VisibleForTesting;
/**
* Used to represent the viewport for a frame in the paint preview player. There should be one of
* these objects per player frame and it should be shared between various classes that manipulated
* the location. Should only be accessed on the UI thread to avoid the need for locks.
*/
public class PlayerFrameViewport {
/** The size of the viewport. */
private Size mViewportSize;
/** A 3x3 affine transformation matrix to track scale and translation. */
@VisibleForTesting
final Matrix mViewportTransform;
/** Transient storage objects to avoid allocations. */
private final Rect mViewportRect = new Rect();
private final float[] mMatrixValues = new float[9];
PlayerFrameViewport(Size size, Matrix matrix) {
mViewportSize = size;
mViewportTransform = matrix;
}
/**
* @return the width of the viewport.
*/
int getWidth() {
return mViewportSize.getWidth();
}
/**
* @return the height of the viewport.
*/
int getHeight() {
return mViewportSize.getHeight();
}
/**
* Returns the size of the viewport. Use with caution as the values of the returned object are
* not updated.
* @return the size of the viewport.
*/
Size getSize() {
return mViewportSize;
}
/**
* Returns the translation of the viewport in the X direction (AKA left).
* @return the x translation of the viewport.
*/
float getTransX() {
mViewportTransform.getValues(mMatrixValues);
return mMatrixValues[Matrix.MTRANS_X];
}
/**
* Returns the translation of the viewport in the Y direction (AKA top).
* @return the y translation of the viewport.
*/
float getTransY() {
mViewportTransform.getValues(mMatrixValues);
return mMatrixValues[Matrix.MTRANS_Y];
}
/**
* Returns the scale at which to show contents.
* @return a scale factor for the viewport.
*/
float getScale() {
mViewportTransform.getValues(mMatrixValues);
return mMatrixValues[Matrix.MSCALE_X]; // x and y should be identical here.
}
/**
* Returns the current viewport position as a rect. Use cautiously as this is an instantaneous
* snapshot and is not continually updated.
* @return a rect of the current viewport.
* */
Rect asRect() {
mViewportTransform.getValues(mMatrixValues);
final int left = Math.round(mMatrixValues[Matrix.MTRANS_X]);
final int top = Math.round(mMatrixValues[Matrix.MTRANS_Y]);
mViewportRect.set(
left, top, left + mViewportSize.getWidth(), top + mViewportSize.getHeight());
return mViewportRect;
}
/**
* Sets the size of the viewport.
* @param width The width of the viewport.
* @param height The height of the viewport.
*/
void setSize(int width, int height) {
mViewportSize = new Size(width, height);
}
/**
* Sets the position x, y (left, top) of the viewport.
* @param x The left side of the viewport.
* @param y The top of the viewport.
*/
void setTrans(float x, float y) {
mViewportTransform.getValues(mMatrixValues);
mMatrixValues[Matrix.MTRANS_X] = x;
mMatrixValues[Matrix.MTRANS_Y] = y;
mViewportTransform.setValues(mMatrixValues);
}
/**
* Sets the scale of the viewport.
* @param scaleFactor The scale of the viewport.
*/
void setScale(float scaleFactor) {
mViewportTransform.getValues(mMatrixValues);
mMatrixValues[Matrix.MSCALE_X] = scaleFactor;
mMatrixValues[Matrix.MSCALE_Y] = scaleFactor;
mViewportTransform.setValues(mMatrixValues);
}
/**
* Offsets/shifts the viewport by a set amount.
* @param dx The distance to offset on the x-axis.
* @param dy The distance to offset on the y-axis.
*/
void offset(float dx, float dy) {
mViewportTransform.postTranslate(dx, dy);
}
/**
* Affine scaling of the viewport about a focal point/pivot.
* @param scaleFactor The amount to scale by (relative to the current scale).
* @param focalX The x-coordinate of the focal point.
* @param focalY The y-coordinate of the focal point.
*/
void scale(float scaleFactor, float focalX, float focalY) {
mViewportTransform.postScale(scaleFactor, scaleFactor, -focalX, -focalY);
}
}
...@@ -376,8 +376,7 @@ public class PlayerFrameMediatorTest { ...@@ -376,8 +376,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[0][0] = true; expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true; expectedRequiredBitmaps[0][1] = true;
expectedRequiredBitmaps[1][0] = true; expectedRequiredBitmaps[1][0] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
mMediator.scrollBy(10, 15); mMediator.scrollBy(10, 15);
// The current viewport covers portions of the 4 top left bitmap tiles. // The current viewport covers portions of the 4 top left bitmap tiles.
...@@ -398,8 +397,7 @@ public class PlayerFrameMediatorTest { ...@@ -398,8 +397,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[1][2] = true; expectedRequiredBitmaps[1][2] = true;
expectedRequiredBitmaps[2][0] = true; expectedRequiredBitmaps[2][0] = true;
expectedRequiredBitmaps[2][1] = true; expectedRequiredBitmaps[2][1] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
mMediator.scrollBy(200, 400); mMediator.scrollBy(200, 400);
// The current view port contains portions of the middle 4 tiles. // The current view port contains portions of the middle 4 tiles.
...@@ -432,8 +430,7 @@ public class PlayerFrameMediatorTest { ...@@ -432,8 +430,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[3][4] = true; expectedRequiredBitmaps[3][4] = true;
expectedRequiredBitmaps[4][2] = true; expectedRequiredBitmaps[4][2] = true;
expectedRequiredBitmaps[4][3] = true; expectedRequiredBitmaps[4][3] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
mMediator.scrollBy(200, 400); mMediator.scrollBy(200, 400);
// The current view port contains portions of the 4 bottom right tiles. // The current view port contains portions of the 4 bottom right tiles.
...@@ -467,8 +464,7 @@ public class PlayerFrameMediatorTest { ...@@ -467,8 +464,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[5][3] = true; expectedRequiredBitmaps[5][3] = true;
expectedRequiredBitmaps[5][4] = true; expectedRequiredBitmaps[5][4] = true;
expectedRequiredBitmaps[5][5] = true; expectedRequiredBitmaps[5][5] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
} }
/** /**
...@@ -791,8 +787,7 @@ public class PlayerFrameMediatorTest { ...@@ -791,8 +787,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[0][0] = true; expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true; expectedRequiredBitmaps[0][1] = true;
expectedRequiredBitmaps[1][0] = true; expectedRequiredBitmaps[1][0] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
// Now a scale factor of 2 will be applied. This will happen at a focal point of 0, 0. // Now a scale factor of 2 will be applied. This will happen at a focal point of 0, 0.
// The same bitmaps will be required but the grid will be double the size. // The same bitmaps will be required but the grid will be double the size.
...@@ -803,9 +798,7 @@ public class PlayerFrameMediatorTest { ...@@ -803,9 +798,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[0][0] = true; expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true; expectedRequiredBitmaps[0][1] = true;
expectedRequiredBitmaps[1][0] = true; expectedRequiredBitmaps[1][0] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(2f)));
Assert.assertNull(mMediator.mRequiredBitmaps.get(1f));
// Reduce the scale factor by 0.5 returning to a scale of 1. // Reduce the scale factor by 0.5 returning to a scale of 1.
Assert.assertTrue(mMediator.scaleBy(0.5f, 0, 0)); Assert.assertTrue(mMediator.scaleBy(0.5f, 0, 0));
...@@ -815,9 +808,7 @@ public class PlayerFrameMediatorTest { ...@@ -815,9 +808,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[0][0] = true; expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true; expectedRequiredBitmaps[0][1] = true;
expectedRequiredBitmaps[1][0] = true; expectedRequiredBitmaps[1][0] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
Assert.assertNull(mMediator.mRequiredBitmaps.get(2f));
// Increase the scale factor to 6 which is above the maximum limit returning to a scale // Increase the scale factor to 6 which is above the maximum limit returning to a scale
// of 5. Note that the grid is smaller than 30x30 as the viewport is not a multiple of the // of 5. Note that the grid is smaller than 30x30 as the viewport is not a multiple of the
...@@ -829,9 +820,7 @@ public class PlayerFrameMediatorTest { ...@@ -829,9 +820,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[0][0] = true; expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true; expectedRequiredBitmaps[0][1] = true;
expectedRequiredBitmaps[1][0] = true; expectedRequiredBitmaps[1][0] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(5f)));
Assert.assertNull(mMediator.mRequiredBitmaps.get(1f));
// Reduce the scale factor back to 1. // Reduce the scale factor back to 1.
Assert.assertTrue(mMediator.scaleBy(0.2f, 0, 0)); Assert.assertTrue(mMediator.scaleBy(0.2f, 0, 0));
...@@ -841,9 +830,7 @@ public class PlayerFrameMediatorTest { ...@@ -841,9 +830,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[0][0] = true; expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true; expectedRequiredBitmaps[0][1] = true;
expectedRequiredBitmaps[1][0] = true; expectedRequiredBitmaps[1][0] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
Assert.assertNull(mMediator.mRequiredBitmaps.get(5f));
// We now reduce the scale factor to less than mInitialScaleFactor; however, the maximum // We now reduce the scale factor to less than mInitialScaleFactor; however, the maximum
// scale out is limited to mInitialScaleFactor. // scale out is limited to mInitialScaleFactor.
...@@ -855,9 +842,7 @@ public class PlayerFrameMediatorTest { ...@@ -855,9 +842,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps = new boolean[2][1]; expectedRequiredBitmaps = new boolean[2][1];
expectedRequiredBitmaps[0][0] = true; expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[1][0] = true; expectedRequiredBitmaps[1][0] = true;
Assert.assertTrue(Arrays.deepEquals( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(initialScaleFactor)));
Assert.assertNull(mMediator.mRequiredBitmaps.get(1f));
} }
/** /**
...@@ -898,11 +883,10 @@ public class PlayerFrameMediatorTest { ...@@ -898,11 +883,10 @@ public class PlayerFrameMediatorTest {
new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 0, 1), 1f)); new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 0, 1), 1f));
// Both matricies should be identity to start. // Both matricies should be identity to start.
Assert.assertTrue(mMediator.mViewportScaleMatrix.isIdentity()); Assert.assertTrue(mMediator.mViewport.mViewportTransform.isIdentity());
Assert.assertTrue(mModel.get(PlayerFrameProperties.SCALE_MATRIX).isIdentity()); Assert.assertTrue(mModel.get(PlayerFrameProperties.SCALE_MATRIX).isIdentity());
// Ensure the correct bitmaps are required and requested. // Ensure the correct bitmaps are required and requested.
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap); Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
// STEP 2: Scroll slightly. // STEP 2: Scroll slightly.
...@@ -925,8 +909,7 @@ public class PlayerFrameMediatorTest { ...@@ -925,8 +909,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[1][2] = true; expectedRequiredBitmaps[1][2] = true;
expectedRequiredBitmaps[2][0] = true; expectedRequiredBitmaps[2][0] = true;
expectedRequiredBitmaps[2][1] = true; expectedRequiredBitmaps[2][1] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
expectedRequestedBitmaps.add( expectedRequestedBitmaps.add(
new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 1, 1), 1f)); new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 1, 1), 1f));
...@@ -944,11 +927,11 @@ public class PlayerFrameMediatorTest { ...@@ -944,11 +927,11 @@ public class PlayerFrameMediatorTest {
Matrix expectedViewportMatrix = new Matrix(); Matrix expectedViewportMatrix = new Matrix();
float[] expectedViewportMatrixValues = new float[9]; float[] expectedViewportMatrixValues = new float[9];
expectedViewportMatrix.getValues(expectedViewportMatrixValues); expectedViewportMatrix.getValues(expectedViewportMatrixValues);
expectedViewportMatrixValues[Matrix.MTRANS_X] = -10; expectedViewportMatrixValues[Matrix.MTRANS_X] = 10;
expectedViewportMatrixValues[Matrix.MTRANS_Y] = -15; expectedViewportMatrixValues[Matrix.MTRANS_Y] = 15;
expectedViewportMatrix.setValues(expectedViewportMatrixValues); expectedViewportMatrix.setValues(expectedViewportMatrixValues);
Assert.assertEquals(expectedViewportMatrix, mMediator.mViewportScaleMatrix); Assert.assertEquals(expectedViewportMatrix, mMediator.mViewport.mViewportTransform);
Assert.assertTrue(mModel.get(PlayerFrameProperties.SCALE_MATRIX).isIdentity()); Assert.assertTrue(mModel.get(PlayerFrameProperties.SCALE_MATRIX).isIdentity());
// STEP 3: Now a scale factor of 2 will be applied. This will happen at a focal point of 50, // STEP 3: Now a scale factor of 2 will be applied. This will happen at a focal point of 50,
...@@ -956,10 +939,10 @@ public class PlayerFrameMediatorTest { ...@@ -956,10 +939,10 @@ public class PlayerFrameMediatorTest {
Assert.assertTrue(mMediator.scaleBy(2f, 50f, 100f)); Assert.assertTrue(mMediator.scaleBy(2f, 50f, 100f));
// Before the scaling commits both matricies should update. // Before the scaling commits both matricies should update.
expectedViewportMatrix.postScale(2f, 2f, 50f, 100f); expectedViewportMatrix.postScale(2f, 2f, -50f, -100f);
Matrix expectedBitmapMatrix = new Matrix(); Matrix expectedBitmapMatrix = new Matrix();
expectedBitmapMatrix.postScale(2f, 2f, 50f, 100f); expectedBitmapMatrix.postScale(2f, 2f, 50f, 100f);
Assert.assertEquals(expectedViewportMatrix, mMediator.mViewportScaleMatrix); Assert.assertEquals(expectedViewportMatrix, mMediator.mViewport.mViewportTransform);
Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX)); Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX));
// Bitmaps should be the same as before scaling until scaling is finished. // Bitmaps should be the same as before scaling until scaling is finished.
...@@ -978,9 +961,7 @@ public class PlayerFrameMediatorTest { ...@@ -978,9 +961,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[1][2] = true; expectedRequiredBitmaps[1][2] = true;
expectedRequiredBitmaps[2][0] = true; expectedRequiredBitmaps[2][0] = true;
expectedRequiredBitmaps[2][1] = true; expectedRequiredBitmaps[2][1] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(2f)));
Assert.assertNull(mMediator.mRequiredBitmaps.get(1f));
expectedRequestedBitmaps.add( expectedRequestedBitmaps.add(
new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 0, 0), 2f)); new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 0, 0), 2f));
...@@ -1009,9 +990,9 @@ public class PlayerFrameMediatorTest { ...@@ -1009,9 +990,9 @@ public class PlayerFrameMediatorTest {
Assert.assertTrue(mMediator.scaleBy(0.5f, 50f, 100f)); Assert.assertTrue(mMediator.scaleBy(0.5f, 50f, 100f));
// Ensure the matricies are correct mid-scale. // Ensure the matricies are correct mid-scale.
expectedViewportMatrix.postScale(0.5f, 0.5f, 50f, 100f); expectedViewportMatrix.postScale(0.5f, 0.5f, -50f, -100f);
expectedBitmapMatrix.postScale(0.5f, 0.5f, 50f, 100f); expectedBitmapMatrix.postScale(0.5f, 0.5f, 50f, 100f);
Assert.assertEquals(expectedViewportMatrix, mMediator.mViewportScaleMatrix); Assert.assertEquals(expectedViewportMatrix, mMediator.mViewport.mViewportTransform);
Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX)); Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX));
// Bitmaps should be the same as before scaling until scaling is finished. // Bitmaps should be the same as before scaling until scaling is finished.
...@@ -1030,9 +1011,7 @@ public class PlayerFrameMediatorTest { ...@@ -1030,9 +1011,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[1][2] = true; expectedRequiredBitmaps[1][2] = true;
expectedRequiredBitmaps[2][0] = true; expectedRequiredBitmaps[2][0] = true;
expectedRequiredBitmaps[2][1] = true; expectedRequiredBitmaps[2][1] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
Assert.assertNull(mMediator.mRequiredBitmaps.get(2f));
expectedRequestedBitmaps.add( expectedRequestedBitmaps.add(
new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 0, 0), 1f)); new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 0, 0), 1f));
...@@ -1071,9 +1050,9 @@ public class PlayerFrameMediatorTest { ...@@ -1071,9 +1050,9 @@ public class PlayerFrameMediatorTest {
// | | | | | | | // | | | | | | |
Assert.assertTrue(mMediator.scaleBy(2f, 100f, 200f)); Assert.assertTrue(mMediator.scaleBy(2f, 100f, 200f));
expectedViewportMatrix.postScale(2f, 2f, 100f, 200f); expectedViewportMatrix.postScale(2f, 2f, -100f, -200f);
expectedBitmapMatrix.postScale(2f, 2f, 100f, 200f); expectedBitmapMatrix.postScale(2f, 2f, 100f, 200f);
Assert.assertEquals(expectedViewportMatrix, mMediator.mViewportScaleMatrix); Assert.assertEquals(expectedViewportMatrix, mMediator.mViewport.mViewportTransform);
Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX)); Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX));
Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap); Assert.assertEquals(expectedRequestedBitmaps, mCompositorDelegate.mRequestedBitmap);
...@@ -1095,9 +1074,7 @@ public class PlayerFrameMediatorTest { ...@@ -1095,9 +1074,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[2][3] = true; expectedRequiredBitmaps[2][3] = true;
expectedRequiredBitmaps[3][1] = true; expectedRequiredBitmaps[3][1] = true;
expectedRequiredBitmaps[3][2] = true; expectedRequiredBitmaps[3][2] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(2f)));
Assert.assertNull(mMediator.mRequiredBitmaps.get(1f));
expectedRequestedBitmaps.add( expectedRequestedBitmaps.add(
new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 1, 1), 2f)); new RequestedBitmap(mFrameGuid, getRectForTile(100, 200, 1, 1), 2f));
...@@ -1205,8 +1182,8 @@ public class PlayerFrameMediatorTest { ...@@ -1205,8 +1182,8 @@ public class PlayerFrameMediatorTest {
// Scale out keeping the subframes in the viewport.. // Scale out keeping the subframes in the viewport..
Assert.assertTrue(mMediator.scaleBy(0.75f, 25f, 50f)); Assert.assertTrue(mMediator.scaleBy(0.75f, 25f, 50f));
expectedRects.clear(); expectedRects.clear();
expectedRects.add(new Rect(6, 13, 81, 43)); expectedRects.add(new Rect(6, 12, 81, 42));
expectedRects.add(new Rect(36, 58, 96, 223)); expectedRects.add(new Rect(36, 57, 96, 222));
Assert.assertEquals(expectedViews, mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS)); Assert.assertEquals(expectedViews, mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS));
Assert.assertEquals(expectedRects, mModel.get(PlayerFrameProperties.SUBFRAME_RECTS)); Assert.assertEquals(expectedRects, mModel.get(PlayerFrameProperties.SUBFRAME_RECTS));
Assert.assertEquals(expectedVisibility, Assert.assertEquals(expectedVisibility,
...@@ -1246,8 +1223,7 @@ public class PlayerFrameMediatorTest { ...@@ -1246,8 +1223,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[0][0] = true; expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true; expectedRequiredBitmaps[0][1] = true;
expectedRequiredBitmaps[1][0] = true; expectedRequiredBitmaps[1][0] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
// Now a scale factor of 2 will be applied. This will happen at a focal point of 0, 0. // Now a scale factor of 2 will be applied. This will happen at a focal point of 0, 0.
// The same bitmaps will be required but the grid will be double the size. // The same bitmaps will be required but the grid will be double the size.
...@@ -1256,7 +1232,7 @@ public class PlayerFrameMediatorTest { ...@@ -1256,7 +1232,7 @@ public class PlayerFrameMediatorTest {
Matrix expectedBitmapMatrix = new Matrix(); Matrix expectedBitmapMatrix = new Matrix();
expectedViewportMatrix.postScale(2f, 2f, 0f, 0f); expectedViewportMatrix.postScale(2f, 2f, 0f, 0f);
expectedBitmapMatrix.postScale(2f, 2f, 0f, 0f); expectedBitmapMatrix.postScale(2f, 2f, 0f, 0f);
Assert.assertEquals(expectedViewportMatrix, mMediator.mViewportScaleMatrix); Assert.assertEquals(expectedViewportMatrix, mMediator.mViewport.mViewportTransform);
Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX)); Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX));
Assert.assertTrue(mMediator.scaleFinished(1f, 0, 0)); Assert.assertTrue(mMediator.scaleFinished(1f, 0, 0));
...@@ -1265,9 +1241,7 @@ public class PlayerFrameMediatorTest { ...@@ -1265,9 +1241,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[0][0] = true; expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true; expectedRequiredBitmaps[0][1] = true;
expectedRequiredBitmaps[1][0] = true; expectedRequiredBitmaps[1][0] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(2f)));
Assert.assertNull(mMediator.mRequiredBitmaps.get(1f));
// Reduce the scale factor by 0.5 returning to a scale of 1 but try to do so with a focal // Reduce the scale factor by 0.5 returning to a scale of 1 but try to do so with a focal
// point that causes translation outside the bounds. The focal point should be ignored. // point that causes translation outside the bounds. The focal point should be ignored.
...@@ -1275,7 +1249,7 @@ public class PlayerFrameMediatorTest { ...@@ -1275,7 +1249,7 @@ public class PlayerFrameMediatorTest {
expectedViewportMatrix.postScale(0.5f, 0.5f, 0f, 0f); expectedViewportMatrix.postScale(0.5f, 0.5f, 0f, 0f);
expectedBitmapMatrix.reset(); expectedBitmapMatrix.reset();
expectedBitmapMatrix.postScale(0.5f, 0.5f, 0f, 0f); expectedBitmapMatrix.postScale(0.5f, 0.5f, 0f, 0f);
Assert.assertEquals(expectedViewportMatrix, mMediator.mViewportScaleMatrix); Assert.assertEquals(expectedViewportMatrix, mMediator.mViewport.mViewportTransform);
Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX)); Assert.assertEquals(expectedBitmapMatrix, mModel.get(PlayerFrameProperties.SCALE_MATRIX));
Assert.assertTrue(mMediator.scaleFinished(1f, -50f, -50f)); Assert.assertTrue(mMediator.scaleFinished(1f, -50f, -50f));
...@@ -1284,9 +1258,7 @@ public class PlayerFrameMediatorTest { ...@@ -1284,9 +1258,7 @@ public class PlayerFrameMediatorTest {
expectedRequiredBitmaps[0][0] = true; expectedRequiredBitmaps[0][0] = true;
expectedRequiredBitmaps[0][1] = true; expectedRequiredBitmaps[0][1] = true;
expectedRequiredBitmaps[1][0] = true; expectedRequiredBitmaps[1][0] = true;
Assert.assertTrue( Assert.assertTrue(Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps));
Arrays.deepEquals(expectedRequiredBitmaps, mMediator.mRequiredBitmaps.get(1f)));
Assert.assertNull(mMediator.mRequiredBitmaps.get(2f));
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment