Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(571)

Side by Side Diff: remoting/android/java/src/org/chromium/chromoting/DesktopCanvas.java

Issue 2441723004: [Android][Client] Updating the calculations used for image overpanning (Closed)
Patch Set: Addressing CR Feedback Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chromoting; 5 package org.chromium.chromoting;
6 6
7 import android.graphics.Matrix; 7 import android.graphics.Matrix;
8 import android.graphics.PointF; 8 import android.graphics.PointF;
9 import android.graphics.Rect; 9 import android.graphics.Rect;
10 import android.graphics.RectF; 10 import android.graphics.RectF;
11 11
12 /** 12 /**
13 * This class is responsible for transforming the desktop image matrix. 13 * This class is responsible for transforming the desktop image matrix.
14 */ 14 */
15 public class DesktopCanvas { 15 public class DesktopCanvas {
16 /** 16 /** Used for floating point comparisons. */
17 * Maximum allowed zoom level - see {@link #scaleAndRepositionImage()}. 17 private static final float EPSILON = 0.0001f;
18 */ 18
19 /** Maximum allowed zoom level - see {@link #scaleAndRepositionImage()}. */
19 private static final float MAX_ZOOM_FACTOR = 100.0f; 20 private static final float MAX_ZOOM_FACTOR = 100.0f;
20 21
21 /** 22 /** Used to smoothly reduce the viewport offset. */
22 * Used to smoothly reduce the amount of padding while the user is zooming. 23 private static final float VIEWPORT_OFFSET_REDUCTION_FACTOR = 0.85f;
23 */ 24
24 private static final float PADDING_REDUCTION_FACTOR = 0.85f; 25 /** Used to terminate the viewport offset animation once this value has been reached. */
26 private static final float MINIMUM_VIEWPORT_OFFSET_PIXELS = 1;
25 27
26 private final RenderStub mRenderStub; 28 private final RenderStub mRenderStub;
27 private final RenderData mRenderData; 29 private final RenderData mRenderData;
28 30
29 /** 31 /**
30 * Represents the actual center of the viewport in image space. This value needs to be a pair
31 * of floats so the desktop image can be positioned with sub-pixel accuracy for smoother panning
32 * animations at high zoom levels.
33 */
34 // TODO(joedow): See if we can collapse Viewport and Cursor position members . They were needed
35 // in the past due to how we calculated the center positions but may not be needed now.
36 private PointF mViewportPosition = new PointF();
37
38 /**
39 * Represents the desired center of the viewport in image space. This value may not represent 32 * Represents the desired center of the viewport in image space. This value may not represent
40 * the actual center of the viewport as adjustments are made to ensure as mu ch of the desktop is 33 * the actual center of the viewport as adjustments are made to ensure as mu ch of the desktop is
41 * visible as possible. This value needs to be a pair of floats so the desk top image can be 34 * visible as possible. This value needs to be a pair of floats so the desk top image can be
42 * positioned with sub-pixel accuracy for smoother panning animations at hig h zoom levels. 35 * positioned with sub-pixel accuracy for smoother panning animations at hig h zoom levels.
43 * Note: The internal cursor position may be placed outside of the image bou ndary, however the
44 * cursor position we inject on the host side is restricted to the actual im age dimensions.
45 */ 36 */
46 private PointF mCursorPosition = new PointF(); 37 private PointF mCursorPosition = new PointF();
Yuwei 2016/10/25 08:25:26 Maybe not for this CL. If this is the desired cent
joedow 2016/10/25 16:49:50 Lambros and I have talked about this a bit already
47 38
48 /** 39 /**
49 * Represents the amount of space, in pixels, used by System UI on each edge of the screen. 40 * If System UI exists, this contains the area of the screen which is unobsc ured by it,
41 * otherwise it is empty.
50 */ 42 */
51 // TODO(joedow): Update usage of this member so it is a true Rect instead of a set of offsets. 43 private Rect mSystemUiScreenRect = new Rect();
52 private Rect mSystemUiScreenSize = new Rect();
53 44
54 /** 45 /**
55 * Represents the amount of padding, in screen pixels, added to each edge of the desktop image. 46 * Represents the amount of space, in pixels, to shift the image under the v iewport. This value
56 * This extra space allows the user to reveal portions of the desktop image which are obscured 47 * is used to allow panning the image further than would be possible when us ing the normal
57 * by System UI. 48 * boundary values to account for System UI. This functionality ensures the user can view and
49 * interact with any area of the remote image, even when System UI might oth erwise obscure it.
58 */ 50 */
59 private RectF mVisibleImagePadding = new RectF(); 51 private PointF mViewportOffset = new PointF();
60 52
61 /** 53 /**
62 * Tracks whether to adjust the viewport to account for System UI. If false, the viewport 54 * Tracks whether to adjust the size of the viewport to account for System U I. If false, the
63 * center is the center of the screen. If true, then System UI offsets will be used to 55 * viewport center is mapped to the center of the screen. If true, then Sys tem UI sizes will be
64 * adjust the position of the viewport to ensure the cursor is visible. 56 * used to determine the center of the viewport.
65 */ 57 */
66 private boolean mAdjustViewportForSystemUi = false; 58 private boolean mAdjustViewportSizeForSystemUi = false;
67 59
68 /** 60 /* Used to perform per-frame rendering tasks. */
69 * Represents the amount of space, in pixels, to adjust the cursor center alo ng the y-axis. 61 private Event.ParameterCallback<Boolean, Void> mFrameRenderedCallback;
70 */
71 private float mCursorOffsetScreenY = 0.0f;
72 62
73 public DesktopCanvas(RenderStub renderStub, RenderData renderData) { 63 public DesktopCanvas(RenderStub renderStub, RenderData renderData) {
74 mRenderStub = renderStub; 64 mRenderStub = renderStub;
75 mRenderData = renderData; 65 mRenderData = renderData;
76 } 66 }
77 67
78 /** 68 /**
79 * Sets the desired center position of the viewport (a.k.a. the cursor posit ion) and ensures 69 * Sets the desired center position of the viewport (a.k.a. the cursor posit ion).
80 * the viewport is updated to include the cursor within it.
81 * 70 *
82 * @param newX The new x coordinate value for the desired center position. 71 * @param newX The new x coordinate value for the desired center position.
83 * @param newY The new y coordinate value for the desired center position. 72 * @param newY The new y coordinate value for the desired center position.
84 */ 73 */
85 public void setCursorPosition(float newX, float newY) { 74 public void setCursorPosition(float newX, float newY) {
86 // First set the cursor position since its potential values are a supers et of the viewport. 75 updateCursorPosition(newX, newY, getImageBounds());
87 mCursorPosition.set(newX, newY); 76 }
88 constrainPointToBounds(mCursorPosition, getImageBounds());
89 77
90 // Now set the viewport position based on the cursor. 78 /**
91 mViewportPosition.set(mCursorPosition); 79 * Sets the center of the viewport using an absolute position (in image coor dinates).
92 constrainPointToBounds(mViewportPosition, getViewportBounds()); 80 *
81 * @param newX The new x coordinate value for the center position of the vie wport.
82 * @param newY The new y coordinate value for the center position of the vie wport.
83 */
84 public void setViewportCenter(float newX, float newY) {
85 updateCursorPosition(newX, newY, getViewportBounds());
86 }
93 87
94 repositionImage(); 88 /**
89 * Shifts the cursor by the passed in values (in image coordinates).
90 *
91 * @param deltaX The distance (in image coordinates) to move the cursor alon g the x-axis.
92 * @param deltaY The distance (in image coordinates) to move the cursor alon g the y-axis.
93 * @return A point representing the new cursor position.
94 */
95 public PointF moveCursorPosition(float deltaX, float deltaY) {
96 updateCursorPosition(
97 mCursorPosition.x + deltaX, mCursorPosition.y + deltaY, getImage Bounds());
98 return new PointF(mCursorPosition.x, mCursorPosition.y);
95 } 99 }
96 100
97 /** 101 /**
98 * Shifts the viewport by the passed in values (in image coordinates). 102 * Shifts the viewport by the passed in values (in image coordinates).
99 * 103 *
100 * @param deltaX The distance (in image coordinates) to move the viewport al ong the x-axis. 104 * @param deltaX The distance (in image coordinates) to move the viewport al ong the x-axis.
101 * @param deltaY The distance (in image coordinates) to move the viewport al ong the y-axis. 105 * @param deltaY The distance (in image coordinates) to move the viewport al ong the y-axis.
102 */ 106 */
103 public void moveViewportCenter(float deltaX, float deltaY) { 107 public void moveViewportCenter(float deltaX, float deltaY) {
104 // Offset and adjust the viewport center position to fit the screen. 108 updateCursorPosition(
105 mViewportPosition.offset(deltaX, deltaY); 109 mCursorPosition.x + deltaX, mCursorPosition.y + deltaY, getViewp ortBounds());
106 constrainPointToBounds(mViewportPosition, getViewportBounds());
107
108 // We don't need to constrain the cursor position as the viewport positi on is always within
109 // the bounds of the potential cursor positions.
110 mCursorPosition.set(mViewportPosition);
111
112 repositionImage();
113 }
114
115 /**
116 * Shifts the cursor by the passed in values (in image coordinates) and adju sts the viewport.
117 *
118 * @param deltaX The distance (in image coordinates) to move the cursor alon g the x-axis.
119 * @param deltaY The distance (in image coordinates) to move the cursor alon g the y-axis.
120 * @return A point representing the new cursor position.
121 */
122 public PointF moveCursorPosition(float deltaX, float deltaY) {
123 setCursorPosition(mCursorPosition.x + deltaX, mCursorPosition.y + deltaY );
124 return new PointF(mCursorPosition.x, mCursorPosition.y);
125 } 110 }
126 111
127 /** 112 /**
128 * Handles System UI size and visibility changes. 113 * Handles System UI size and visibility changes.
129 * 114 *
130 * @param parameter The set of values defining the current System UI state. 115 * @param parameter The set of values defining the current System UI state.
131 */ 116 */
132 public void onSystemUiVisibilityChanged(SystemUiVisibilityChangedEventParame ter parameter) { 117 public void onSystemUiVisibilityChanged(SystemUiVisibilityChangedEventParame ter parameter) {
133 if (parameter.softInputMethodVisible) { 118 if (parameter.softInputMethodVisible) {
134 mSystemUiScreenSize.set(parameter.left, parameter.top, 119 mSystemUiScreenRect.set(
135 mRenderData.screenWidth - parameter.right, 120 parameter.left, parameter.top, parameter.right, parameter.bo ttom);
136 mRenderData.screenHeight - parameter.bottom);
137 121
138 if (mAdjustViewportForSystemUi) { 122 stopOffsetReductionAnimation();
139 // Adjust the cursor position to ensure it's visible when large System UI (1/3 or 123 } else {
140 // more of the total screen size) is displayed (typically the So ft Keyboard). 124 mSystemUiScreenRect.setEmpty();
141 // Without this change, it is difficult for users to enter text into edit controls 125 startOffsetReductionAnimation();
142 // which are located bottom of the screen and may not see the cu rsor at all. 126 }
143 if (mSystemUiScreenSize.bottom > (mRenderData.screenHeight / 3)) {
144 // Center the cursor within the viewable area (not obscured by System UI).
145 mCursorOffsetScreenY = (float) parameter.bottom / 2.0f;
146 } else {
147 mCursorOffsetScreenY = 0.0f;
148 }
149 127
150 // Apply the cursor offset. 128 repositionImage();
151 setCursorPosition(mCursorPosition.x, mCursorPosition.y);
152 }
153 } else {
154 mCursorOffsetScreenY = 0.0f;
155 mSystemUiScreenSize.setEmpty();
156 }
157 } 129 }
158 130
159 public void adjustViewportForSystemUi(boolean adjustViewportForSystemUi) { 131 public void adjustViewportForSystemUi(boolean adjustViewportForSystemUi) {
160 mAdjustViewportForSystemUi = adjustViewportForSystemUi; 132 mAdjustViewportSizeForSystemUi = adjustViewportForSystemUi;
133
134 // The viewport center may have changed so reposition the image to refle ct the new value.
135 repositionImage();
161 } 136 }
162 137
163 /** Resizes the image by zooming it such that the image is displayed without borders. */ 138 /** Resizes the image by zooming it such that the image is displayed without borders. */
164 public void resizeImageToFitScreen() { 139 public void resizeImageToFitScreen() {
165 // Protect against being called before the image has been initialized. 140 // Protect against being called before the image has been initialized.
166 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) { 141 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) {
167 return; 142 return;
168 } 143 }
169 144
170 float widthRatio = (float) mRenderData.screenWidth / mRenderData.imageWi dth; 145 float widthRatio = (float) mRenderData.screenWidth / mRenderData.imageWi dth;
171 float heightRatio = (float) mRenderData.screenHeight / mRenderData.image Height; 146 float heightRatio = (float) mRenderData.screenHeight / mRenderData.image Height;
172 float screenToImageScale = Math.max(widthRatio, heightRatio); 147 float screenToImageScale = Math.max(widthRatio, heightRatio);
173 148
174 // If the image is smaller than the screen in either dimension, then we want to scale it 149 // If the image is smaller than the screen in either dimension, then we want to scale it
175 // up to fit both and fill the screen with the image of the remote deskt op. 150 // up to fit both and fill the screen with the image of the remote deskt op.
176 if (screenToImageScale > 1.0f) { 151 if (screenToImageScale > 1.0f) {
177 mRenderData.transform.setScale(screenToImageScale, screenToImageScal e); 152 mRenderData.transform.setScale(screenToImageScale, screenToImageScal e);
178 } 153 }
179 } 154 }
180 155
181 /** 156 /**
182 * Repositions the image by translating and zooming it, to keep the zoom lev el within sensible 157 * Repositions the image by translating and zooming it, to keep the zoom lev el within sensible
183 * limits. The minimum zoom level is chosen to avoid black space around all 4 sides. The 158 * limits. The minimum zoom level is chosen to avoid letterboxing on all 4 s ides. The
184 * maximum zoom level is set arbitrarily, so that the user can zoom out agai n in a reasonable 159 * maximum zoom level is set arbitrarily, so that the user can zoom out agai n in a reasonable
185 * time, and to prevent arithmetic overflow problems from displaying the ima ge. 160 * time, and to prevent arithmetic overflow problems from displaying the ima ge.
186 * 161 *
187 * @param scaleFactor The factor used to zoom the canvas in or out. 162 * @param scaleFactor The factor used to zoom the canvas in or out.
188 * @param px The center x coordinate for the scale action. 163 * @param px The center x coordinate for the scale action.
189 * @param py The center y coordinate for the scale action. 164 * @param py The center y coordinate for the scale action.
190 * @param centerOnCursor Determines whether the viewport will be translated to the desired 165 * @param centerOnCursor Determines whether the viewport will be translated to the desired
191 * center position before being adjusted to fit the sc reen boundaries. 166 * center position before being adjusted to fit the sc reen boundaries.
192 */ 167 */
193 public void scaleAndRepositionImage( 168 public void scaleAndRepositionImage(
(...skipping 16 matching lines...) Expand all
210 mRenderData.transform.mapVectors(imageSize); 185 mRenderData.transform.mapVectors(imageSize);
211 186
212 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData .screenHeight) { 187 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData .screenHeight) {
213 // Displayed image is too small in both directions, so apply the min imum zoom 188 // Displayed image is too small in both directions, so apply the min imum zoom
214 // level needed to fit either the width or height. 189 // level needed to fit either the width or height.
215 float scale = Math.min((float) mRenderData.screenWidth / mRenderData .imageWidth, 190 float scale = Math.min((float) mRenderData.screenWidth / mRenderData .imageWidth,
216 (float) mRenderData.screenHeight / mRenderDat a.imageHeight); 191 (float) mRenderData.screenHeight / mRenderDat a.imageHeight);
217 mRenderData.transform.setScale(scale, scale); 192 mRenderData.transform.setScale(scale, scale);
218 } 193 }
219 194
220 // Trim the image padding if the user is zooming out. This prevents cas es where the image
221 // pops to the center when it reaches its minimum size. Note that we do not need to do
222 // anything when the user is zooming in as the canvas will expand and ab sorb the padding.
223 if (scaleFactor < 1.0f) {
224 mVisibleImagePadding.set(mVisibleImagePadding.left * PADDING_REDUCTI ON_FACTOR,
225 mVisibleImagePadding.top * PADDING_REDUCTION_FACTOR,
226 mVisibleImagePadding.right * PADDING_REDUCTION_FACTOR,
227 mVisibleImagePadding.bottom * PADDING_REDUCTION_FACTOR);
228 }
229
230 if (centerOnCursor) { 195 if (centerOnCursor) {
231 setCursorPosition(mCursorPosition.x, mCursorPosition.y); 196 setCursorPosition(mCursorPosition.x, mCursorPosition.y);
232 } else { 197 } else {
233 // Find the new screen center (it was probably changed during the zo om operation) and 198 // Find the new screen center (it probably changed during the zoom o peration) and update
234 // update the viewport and cursor. 199 // the viewport to smoothly track the zoom gesture.
235 float[] mappedPoints = { 200 float[] mappedPoints = {((float) mRenderData.screenWidth / 2) - mVie wportOffset.x,
236 ((float) mRenderData.screenWidth / 2), ((float) mRenderData. screenHeight / 2)}; 201 ((float) mRenderData.screenHeight / 2) - mViewportOffset.y};
237 Matrix screenToImage = new Matrix(); 202 Matrix screenToImage = new Matrix();
238 mRenderData.transform.invert(screenToImage); 203 mRenderData.transform.invert(screenToImage);
239 screenToImage.mapPoints(mappedPoints); 204 screenToImage.mapPoints(mappedPoints);
240 // The cursor is mapped to the center of the viewport in this case. 205 // The cursor is mapped to the center of the viewport in this case.
241 setCursorPosition(mappedPoints[0], mappedPoints[1]); 206 setViewportCenter(mappedPoints[0], mappedPoints[1]);
242 } 207 }
243 } 208 }
244 209
245 /** 210 /**
211 * Sets the new cursor position, bounded by the given rect, and updates the image transform to
212 * reflect the new position.
213 */
214 private void updateCursorPosition(float newX, float newY, RectF bounds) {
215 mCursorPosition.set(newX, newY);
216 constrainPointToBounds(mCursorPosition, bounds);
217
218 calculateViewportOffset(newX - mCursorPosition.x, newY - mCursorPosition .y);
219
220 repositionImage();
221 }
222
223 /**
224 * Returns the height of the screen (in screen coordinates) for use in calcu lations involving
225 * viewport positioning.
226 */
227 private float getAdjustedScreenHeight() {
228 float adjustedScreenHeight;
229 if (mAdjustViewportSizeForSystemUi && !mSystemUiScreenRect.isEmpty()) {
230 // Find the center point of the viewport on the screen.
231 adjustedScreenHeight = mSystemUiScreenRect.bottom;
232 } else {
233 adjustedScreenHeight = ((float) mRenderData.screenHeight);
234 }
235
236 return adjustedScreenHeight;
237 }
238
239 /**
240 * Returns the center position of the viewport (in screen coordinates) inclu ding adjustments.
241 */
242 private PointF getViewportCenter() {
243 return new PointF((float) mRenderData.screenWidth / 2, getAdjustedScreen Height() / 2);
244 }
245
246 /**
246 * Repositions the image by translating it (without affecting the zoom level ). 247 * Repositions the image by translating it (without affecting the zoom level ).
247 */ 248 */
248 private void repositionImage() { 249 private void repositionImage() {
249 // Map the current viewport position to screen coordinates and adjust th e image position. 250 PointF viewportPosition = new PointF(mCursorPosition.x, mCursorPosition. y);
250 float[] viewportPosition = {mViewportPosition.x, mViewportPosition.y}; 251 constrainPointToBounds(viewportPosition, getViewportBounds());
251 mRenderData.transform.mapPoints(viewportPosition); 252 float[] viewportAdjustment = {viewportPosition.x, viewportPosition.y};
253 mRenderData.transform.mapPoints(viewportAdjustment);
252 254
253 float viewportTransX = ((float) mRenderData.screenWidth / 2) - viewportP osition[0]; 255 // Adjust the viewport to include the overpan amount.
254 float viewportTransY = 256 viewportAdjustment[0] += mViewportOffset.x;
255 ((float) mRenderData.screenHeight / 2) - viewportPosition[1] - m CursorOffsetScreenY; 257 viewportAdjustment[1] += mViewportOffset.y;
256 258
257 // Translate the image to move the viewport to the expected screen locat ion. 259 // Translate the image to move the viewport to the expected screen locat ion.
258 mRenderData.transform.postTranslate(viewportTransX, viewportTransY); 260 PointF viewportCenter = getViewportCenter();
259 261 mRenderData.transform.postTranslate(
260 updateVisibleImagePadding(); 262 viewportCenter.x - viewportAdjustment[0], viewportCenter.y - vie wportAdjustment[1]);
261 263
262 mRenderStub.setTransformation(mRenderData.transform); 264 mRenderStub.setTransformation(mRenderData.transform);
263 } 265 }
264 266
265 /** 267 /**
266 * Updates the given point such that it refers to a coordinate within the bo unds provided. 268 * Updates the given point such that it refers to a coordinate within the bo unds provided.
267 * 269 *
268 * @param point The point to adjust, the original object is modified. 270 * @param point The point to adjust, the original object is modified.
269 * @param bounds The bounds used to constrain the point. 271 * @param bounds The bounds used to constrain the point.
270 */ 272 */
271 private void constrainPointToBounds(PointF point, RectF bounds) { 273 private void constrainPointToBounds(PointF point, RectF bounds) {
272 if (point.x < bounds.left) { 274 if (point.x < bounds.left) {
273 point.x = bounds.left; 275 point.x = bounds.left;
274 } else if (point.x > bounds.right) { 276 } else if (point.x > bounds.right) {
275 point.x = bounds.right; 277 point.x = bounds.right;
276 } 278 }
277 279
278 if (point.y < bounds.top) { 280 if (point.y < bounds.top) {
279 point.y = bounds.top; 281 point.y = bounds.top;
280 } else if (point.y > bounds.bottom) { 282 } else if (point.y > bounds.bottom) {
281 point.y = bounds.bottom; 283 point.y = bounds.bottom;
282 } 284 }
283 } 285 }
284 286
285 /** Returns a region which defines the set of valid cursor positions in imag e space. */ 287 /** Returns a region which defines the set of valid cursor positions in imag e space. */
286 private RectF getImageBounds() { 288 private RectF getImageBounds() {
287 // The set of valid cursor positions includes any point on the image as well as the padding. 289 return new RectF(0, 0, mRenderData.imageWidth, mRenderData.imageHeight);
288 // Padding is additional space added to the image which is the larger va lue of:
289 // - Potential overlap of the System UI and image content
290 // - Actual amount of padding already being used
291 //
292 // By expanding the area, we allow the user to move the cursor 'under' t he System UI which
293 // pulls the content out from under it and allows it to be visible. Onc e the System UI has
294 // been dismissed or changes size, we use the actual padding value inste ad which prevents
295 // the desktop image from 'snapping' back to pre-System UI state.
296 RectF systemUiOverlap = getSystemUiOverlap();
297 float[] padding = {Math.max(mVisibleImagePadding.left, systemUiOverlap.l eft),
298 Math.max(mVisibleImagePadding.top + mCursorOffsetScreenY, system UiOverlap.top),
299 Math.max(mVisibleImagePadding.right, systemUiOverlap.right),
300 Math.max(mVisibleImagePadding.bottom - mCursorOffsetScreenY,
301 systemUiOverlap.bottom)};
302 Matrix screenToImage = new Matrix();
303 mRenderData.transform.invert(screenToImage);
304 screenToImage.mapVectors(padding);
305
306 return new RectF(-padding[0], -padding[1], mRenderData.imageWidth + padd ing[2],
307 mRenderData.imageHeight + padding[3]);
308 } 290 }
309 291
310 /** Returns a region which defines the set of valid viewport center values i n image space. */ 292 /** Returns a region which defines the set of valid viewport center values i n image space. */
311 private RectF getViewportBounds() { 293 private RectF getViewportBounds() {
312 // The region of allowable viewport values is the imageBound rect, inset by the size of the 294 // The region of allowable viewport values is the imageBound rect, inset by the size of the
313 // viewport itself. This prevents over and under panning of the viewpor t while still 295 // viewport itself. This prevents over and under panning of the viewpor t while still
314 // allowing the user to see and interact with all pixels one the desktop image. 296 // allowing the user to see and interact with all pixels one the desktop image.
315 Matrix screenToImage = new Matrix(); 297 Matrix screenToImage = new Matrix();
316 mRenderData.transform.invert(screenToImage); 298 mRenderData.transform.invert(screenToImage);
317 299
318 float[] screenVectors = {(float) mRenderData.screenWidth, (float) mRende rData.screenHeight}; 300 PointF viewportCenter = getViewportCenter();
301 float[] screenVectors = {viewportCenter.x, viewportCenter.y};
319 screenToImage.mapVectors(screenVectors); 302 screenToImage.mapVectors(screenVectors);
320 303
321 PointF letterboxPadding = getLetterboxPadding(); 304 PointF letterboxPadding = getLetterboxPadding();
322 float[] letterboxPaddingVectors = {letterboxPadding.x, letterboxPadding. y}; 305 float[] letterboxPaddingVectors = {letterboxPadding.x, letterboxPadding. y};
323 screenToImage.mapVectors(letterboxPaddingVectors); 306 screenToImage.mapVectors(letterboxPaddingVectors);
324 307
325 // screenCenter values are 1/2 of a particular screen dimension mapped t o image space. 308 // screenCenter values are 1/2 of a particular screen dimension mapped t o image space.
326 float screenCenterX = (screenVectors[0] / 2.0f) - letterboxPaddingVector s[0]; 309 float screenCenterX = screenVectors[0] - letterboxPaddingVectors[0];
327 float screenCenterY = (screenVectors[1] / 2.0f) - letterboxPaddingVector s[1]; 310 float screenCenterY = screenVectors[1] - letterboxPaddingVectors[1];
328 RectF imageBounds = getImageBounds(); 311 RectF imageBounds = getImageBounds();
329 imageBounds.inset(screenCenterX, screenCenterY); 312 imageBounds.inset(screenCenterX, screenCenterY);
330 return imageBounds; 313 return imageBounds;
331 } 314 }
332 315
333 /** 316 /**
317 * Returns a region defining the maximum offset distance required to view th e entire image
318 * given the current amount of System UI overlapping it.
319 */
320 private RectF getViewportOffsetBounds() {
321 // The allowable region is determined by:
322 // - Overlap of the System UI and image content
323 // - Current viewport offset
324 //
325 // The System UI overlap represents the maximum allowable offset, this i s used to bound the
326 // viewport movement in each direction. The current offset is used to p revent 'snapping'
327 // the image when the System UI overlap is reduced.
328 RectF viewportOffsetRect = new RectF();
329 viewportOffsetRect.union(mViewportOffset.x, mViewportOffset.y);
330
331 RectF systemUiOverlap = getSystemUiOverlap();
332 return new RectF(Math.min(viewportOffsetRect.left, -systemUiOverlap.left ),
333 Math.min(viewportOffsetRect.top, -systemUiOverlap.top),
334 Math.max(viewportOffsetRect.right, systemUiOverlap.right),
335 Math.max(viewportOffsetRect.bottom, systemUiOverlap.bottom));
336 }
337
338 /**
334 * Provides the amount of padding needed to center the image content on the screen. 339 * Provides the amount of padding needed to center the image content on the screen.
335 */ 340 */
336 private PointF getLetterboxPadding() { 341 private PointF getLetterboxPadding() {
337 float[] imageVectors = {mRenderData.imageWidth, mRenderData.imageHeight} ; 342 float[] imageVectors = {mRenderData.imageWidth, mRenderData.imageHeight} ;
338 mRenderData.transform.mapVectors(imageVectors); 343 mRenderData.transform.mapVectors(imageVectors);
339 344
340 // We want to letterbox when the image is smaller than the screen in a s pecific dimension. 345 // We want to letterbox when the image is smaller than the screen in a s pecific dimension.
341 // Since we center the image, split the difference so it is equally dist ributed. 346 // Since we center the image, split the difference so it is equally dist ributed.
342 float widthAdjust = 347 float widthAdjust = Math.max(((float) mRenderData.screenWidth - imageVec tors[0]) / 2, 0);
343 Math.max(((float) mRenderData.screenWidth - imageVectors[0]) / 2 .0f, 0.0f); 348 float heightAdjust = Math.max((getAdjustedScreenHeight() - imageVectors[ 1]) / 2, 0);
344 float heightAdjust =
345 Math.max(((float) mRenderData.screenHeight - imageVectors[1]) / 2.0f, 0.0f);
346 349
347 return new PointF(widthAdjust, heightAdjust); 350 return new PointF(widthAdjust, heightAdjust);
348 } 351 }
349 352
350 /** 353 /**
351 * Returns the amount of System UI along each edge of the screen which could overlap the remote 354 * Returns the amount of System UI along each edge of the screen which could overlap the remote
352 * desktop image below it. This is the maximum amount that could overlap, n ot the actual value. 355 * desktop image below it. This is the maximum amount that could overlap, n ot the actual value.
353 */ 356 */
354 private RectF getSystemUiOverlap() { 357 private RectF getSystemUiOverlap() {
355 // letterBox padding represents the space added to the image to center i t on the screen. 358 if (mSystemUiScreenRect.isEmpty()) {
359 return new RectF();
360 }
361
362 // LetterBox padding represents the space added to the image to center i t on the screen.
356 // Since it does not contain any interactable UI, we ignore it when calc ulating the overlap 363 // Since it does not contain any interactable UI, we ignore it when calc ulating the overlap
357 // between the System UI and the remote desktop image. 364 // between the System UI and the remote desktop image.
358 // Note: Ignore negative padding (clamp to 0) since that means no overla p exists. 365 // Note: Ignore negative padding (clamp to 0) since that means no overla p exists.
366 float adjustedScreenHeight = getAdjustedScreenHeight();
359 PointF letterboxPadding = getLetterboxPadding(); 367 PointF letterboxPadding = getLetterboxPadding();
360 return new RectF(Math.max(mSystemUiScreenSize.left - letterboxPadding.x, 0.0f), 368 return new RectF(Math.max(mSystemUiScreenRect.left - letterboxPadding.x, 0.0f),
361 Math.max(mSystemUiScreenSize.top - letterboxPadding.y + mCursorO ffsetScreenY, 0.0f), 369 Math.max(mSystemUiScreenRect.top - letterboxPadding.y, 0.0f),
362 Math.max(mSystemUiScreenSize.right - letterboxPadding.x, 0.0f), 370 Math.max(mRenderData.screenWidth - mSystemUiScreenRect.right - l etterboxPadding.x,
363 Math.max(mSystemUiScreenSize.bottom - letterboxPadding.y - mCurs orOffsetScreenY, 371 0.0f),
372 Math.max(adjustedScreenHeight - mSystemUiScreenRect.bottom - let terboxPadding.y,
364 0.0f)); 373 0.0f));
365 } 374 }
366 375
367 /** 376 /**
368 * Calculates the amount of padding visible on each edge of the desktop imag e. 377 * Applies the given offset, as needed, to allow moving the image outside it s normal bounds.
369 */ 378 */
370 private void updateVisibleImagePadding() { 379 private void calculateViewportOffset(float offsetX, float offsetY) {
371 PointF letterboxPadding = getLetterboxPadding(); 380 if (mSystemUiScreenRect.isEmpty()) {
372 float[] imagePoints = {0.0f, 0.0f, mRenderData.imageWidth, mRenderData.i mageHeight}; 381 // We only want to directly change the viewport offset when System U I is present.
373 mRenderData.transform.mapPoints(imagePoints); 382 return;
383 }
374 384
375 mVisibleImagePadding.set(Math.max(imagePoints[0] - letterboxPadding.x, 0 .0f), 385 float[] offsets = {offsetX, offsetY};
376 Math.max(imagePoints[1] - letterboxPadding.y, 0.0f), 386 mRenderData.transform.mapVectors(offsets);
377 Math.max(mRenderData.screenWidth - imagePoints[2] - letterboxPad ding.x, 0.0f), 387
378 Math.max(mRenderData.screenHeight - imagePoints[3] - letterboxPa dding.y, 0.0f)); 388 // Use a temporary variable here as {@link #getViewportOffsetBounds()} u ses the current
389 // viewport offset as a maximum boundary. If we add the offset first, t he result ends up
390 // being unbounded. Thus we use a temporary object for the boundary cal culation.
391 PointF requestedOffset =
392 new PointF(mViewportOffset.x + offsets[0], mViewportOffset.y + o ffsets[1]);
393 constrainPointToBounds(requestedOffset, getViewportOffsetBounds());
394 mViewportOffset.set(requestedOffset);
395 }
396
397 /**
398 * Starts an animation to smoothly reduce the viewport offset. Does nothing if an animation is
399 * already running or the offset is already 0.
400 */
401 private void startOffsetReductionAnimation() {
402 if (mFrameRenderedCallback != null || Math.abs(mViewportOffset.length()) < EPSILON) {
403 return;
404 }
405
406 mFrameRenderedCallback = new Event.ParameterCallback<Boolean, Void>() {
407 @Override
408 public Boolean run(Void p) {
409 mViewportOffset.set(mViewportOffset.x * VIEWPORT_OFFSET_REDUCTIO N_FACTOR,
Yuwei 2016/10/25 08:25:26 The timing implicitly depends on the fact that the
joedow 2016/10/25 16:49:50 I didn't realize the renderer wasn't running at a
Yuwei 2016/10/25 18:19:59 60Hz is more like the highest possible framerate o
410 mViewportOffset.y * VIEWPORT_OFFSET_REDUCTION_FACTOR);
411
412 if (Math.abs(mViewportOffset.length()) < MINIMUM_VIEWPORT_OFFSET _PIXELS) {
413 mViewportOffset.set(0.0f, 0.0f);
414 mFrameRenderedCallback = null;
415 }
416
417 repositionImage();
418
419 return mFrameRenderedCallback != null;
420 }
421 };
422
423 mRenderStub.onCanvasRendered().addSelfRemovable(mFrameRenderedCallback);
424 }
425
426 /**
427 * Stops an existing animation if one is currently running.
428 */
429 private void stopOffsetReductionAnimation() {
430 if (mFrameRenderedCallback == null) {
431 return;
432 }
433
434 mRenderStub.onCanvasRendered().remove(mFrameRenderedCallback);
Yuwei 2016/10/25 08:25:26 This line of code probably doesn't work. addSelfRe
joedow 2016/10/25 16:49:50 Thanks for pointing that out, I can see the intent
Yuwei 2016/10/25 18:19:59 Agreed. We may want to fix the self removable at s
435 mFrameRenderedCallback = null;
379 } 436 }
380 } 437 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698