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

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

Issue 2372663002: Separating cursor and viewport calculations in the desktop canvas (Closed)
Patch Set: Merging with ToT and doing some pre-review clean-up Created 4 years, 2 months 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 | remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java » ('j') | 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 /**
17 * Maximum allowed zoom level - see {@link #repositionImageWithZoom()}. 17 * Maximum allowed zoom level - see {@link #repositionImageWithZoom()}.
18 */ 18 */
19 private static final float MAX_ZOOM_FACTOR = 100.0f; 19 private static final float MAX_ZOOM_FACTOR = 100.0f;
20 20
21 private final RenderStub mRenderStub; 21 private final RenderStub mRenderStub;
22 private final RenderData mRenderData; 22 private final RenderData mRenderData;
23 23
24 /** 24 /**
25 * Represents the actual center of the viewport. This value needs to be a p air of floats so the
26 * desktop image can be positioned with sub-pixel accuracy for smoother pann ing animations at
27 * high zoom levels.
28 */
29 private PointF mViewportPosition = new PointF();
30
31 /**
25 * Represents the desired center of the viewport. This value may not repres ent the actual 32 * Represents the desired center of the viewport. This value may not repres ent the actual
26 * center of the viewport as adjustments are made to ensure as much of the d esktop is visible as 33 * center of the viewport as adjustments are made to ensure as much of the d esktop is visible as
27 * possible. This value needs to be a pair of floats so the desktop image c an be positioned 34 * possible. This value needs to be a pair of floats so the desktop image c an be positioned
28 * with sub-pixel accuracy for smoother panning animations at high zoom leve ls. 35 * with sub-pixel accuracy for smoother panning animations at high zoom leve ls.
29 */ 36 */
30 private PointF mViewportPosition = new PointF(); 37 private PointF mCursorPosition = new PointF();
31 38
32 /** 39 /**
33 * Represents the amount of space, in pixels, used by System UI. 40 * Represents the amount of space, in pixels, used by System UI.
34 */ 41 */
35 private Rect mSystemUiOffsetPixels = new Rect(); 42 private Rect mSystemUiOffsetPixels = new Rect();
36 43
37 public DesktopCanvas(RenderStub renderStub, RenderData renderData) { 44 public DesktopCanvas(RenderStub renderStub, RenderData renderData) {
38 mRenderStub = renderStub; 45 mRenderStub = renderStub;
39 mRenderData = renderData; 46 mRenderData = renderData;
40 } 47 }
41 48
42 /** 49 /**
43 * Shifts the viewport by the passed in deltas (in image coordinates).
44 *
45 * @param useScreenCenter Determines whether to use the desired viewport pos ition or the actual
46 * center of the screen for positioning.
47 * @param deltaX The distance (in image coordinates) to move the viewport al ong the x-axis.
48 * @param deltaY The distance (in image coordinates) to move the viewport al ong the y-axis.
49 * @return A point representing the new center position of the viewport.
50 */
51 public PointF moveViewportCenter(boolean useScreenCenter, float deltaX, floa t deltaY) {
52 PointF viewportCenter;
53 if (useScreenCenter) {
54 viewportCenter = getTrueViewportCenter();
55 } else {
56 viewportCenter = new PointF(mViewportPosition.x, mViewportPosition.y );
57 }
58 viewportCenter.offset(deltaX, deltaY);
59
60 RectF bounds = new RectF(0, 0, mRenderData.imageWidth, mRenderData.image Height);
61
62 if (viewportCenter.x < bounds.left) {
63 viewportCenter.x = bounds.left;
64 } else if (viewportCenter.x > bounds.right) {
65 viewportCenter.x = bounds.right;
66 }
67
68 if (viewportCenter.y < bounds.top) {
69 viewportCenter.y = bounds.top;
70 } else if (viewportCenter.y > bounds.bottom) {
71 viewportCenter.y = bounds.bottom;
72 }
73
74 mViewportPosition.set(viewportCenter);
75
76 return viewportCenter;
77 }
78
79 /**
80 * Sets the desired center position of the viewport. 50 * Sets the desired center position of the viewport.
81 * 51 *
82 * @param newX The new x coordinate value for the desired center position. 52 * @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. 53 * @param newY The new y coordinate value for the desired center position.
84 */ 54 */
85 public void setViewportPosition(float newX, float newY) { 55 public void setViewportCenter(float newX, float newY) {
Lambros 2016/09/27 02:16:37 This should probably be called setCursorAndViewpor
joedow 2016/09/27 20:09:29 Updating the name is fine, but I'd prefer to name
86 mViewportPosition.set(newX, newY); 56 // First set the cursor position since its potential values are a supers et of the viewport.
57 mCursorPosition.set(newX, newY);
58 constrainPointToBounds(mCursorPosition, getImageBounds());
59
60 // Now set the viewport position based on the cursor.
61 mViewportPosition.set(mCursorPosition);
62 constrainPointToBounds(mViewportPosition, getViewportBounds());
87 } 63 }
88 64
89 /** 65 /**
90 * Returns the true center position of the viewport (in image coordinates). 66 * Shifts the viewport by the passed in values (in image coordinates).
91 * 67 *
92 * @return A point representing the true center position of the viewport. 68 * @param deltaX The distance (in image coordinates) to move the viewport al ong the x-axis.
69 * @param deltaY The distance (in image coordinates) to move the viewport al ong the y-axis.
93 */ 70 */
94 private PointF getTrueViewportCenter() { 71 public void moveViewportCenter(float deltaX, float deltaY) {
Lambros 2016/09/27 02:16:37 Clarify this does not actually move the viewport -
joedow 2016/09/27 20:09:29 Acknowledged.
95 // Find the center point of the viewport on the screen. 72 // Offset and adjust the viewport center position to fit the screen.
96 float[] viewportPosition = { 73 mViewportPosition.offset(deltaX, deltaY);
97 ((float) mRenderData.screenWidth / 2), ((float) mRenderData.scre enHeight / 2)}; 74 constrainPointToBounds(mViewportPosition, getViewportBounds());
98 75
99 // Convert the screen position to an image position. 76 // We don't need to constrain the cursor position as the viewport positi on is always within
100 Matrix screenToImage = new Matrix(); 77 // the bounds of the potential cursor positions.
101 mRenderData.transform.invert(screenToImage); 78 mCursorPosition.set(mViewportPosition);
102 screenToImage.mapPoints(viewportPosition);
103 return new PointF(viewportPosition[0], viewportPosition[1]);
104 } 79 }
105 80
106 /** 81 /**
82 * Shifts the cursor by the passed in values (in image coordinates) and adju sts the viewport.
83 *
84 * @param deltaX The distance (in image coordinates) to move the cursor alon g the x-axis.
85 * @param deltaY The distance (in image coordinates) to move the cursor alon g the y-axis.
86 * @return A point representing the new cursor position.
87 */
88 public PointF moveViewportWithCursor(float deltaX, float deltaY) {
Lambros 2016/09/27 02:16:36 Maybe offsetCursorAndSetViewportPosition() ?
joedow 2016/09/27 20:09:29 Renamed based on intention of the caller.
89 setViewportCenter(mCursorPosition.x + deltaX, mCursorPosition.y + deltaY );
90 return new PointF(mCursorPosition.x, mCursorPosition.y);
91 }
92
93 /**
107 * Sets the offset values used to calculate the space used by System UI. 94 * Sets the offset values used to calculate the space used by System UI.
108 * 95 *
109 * @param left The space used by System UI on the left edge of the screen. 96 * @param left The space used by System UI on the left edge of the screen.
110 * @param top The space used by System UI on the top edge of the screen. 97 * @param top The space used by System UI on the top edge of the screen.
111 * @param right The space used by System UI on the right edge of the screen. 98 * @param right The space used by System UI on the right edge of the screen.
112 * @param bottom The space used by System UI on the bottom edge of the scree n. 99 * @param bottom The space used by System UI on the bottom edge of the scree n.
113 */ 100 */
114 public void setSystemUiOffsetValues(int left, int top, int right, int bottom ) { 101 public void setSystemUiOffsetValues(int left, int top, int right, int bottom ) {
115 mSystemUiOffsetPixels.set(left, top, right, bottom); 102 mSystemUiOffsetPixels.set(left, top, right, bottom);
116 } 103 }
(...skipping 12 matching lines...) Expand all
129 116
130 float widthRatio = (float) mRenderData.screenWidth / mRenderData.imageWi dth; 117 float widthRatio = (float) mRenderData.screenWidth / mRenderData.imageWi dth;
131 float heightRatio = (float) mRenderData.screenHeight / mRenderData.image Height; 118 float heightRatio = (float) mRenderData.screenHeight / mRenderData.image Height;
132 float screenToImageScale = Math.max(widthRatio, heightRatio); 119 float screenToImageScale = Math.max(widthRatio, heightRatio);
133 120
134 // If the image is smaller than the screen in either dimension, then we want to scale it 121 // If the image is smaller than the screen in either dimension, then we want to scale it
135 // up to fit both and fill the screen with the image of the remote deskt op. 122 // up to fit both and fill the screen with the image of the remote deskt op.
136 if (screenToImageScale > 1.0f) { 123 if (screenToImageScale > 1.0f) {
137 mRenderData.transform.setScale(screenToImageScale, screenToImageScal e); 124 mRenderData.transform.setScale(screenToImageScale, screenToImageScal e);
138 } 125 }
139
140 repositionImage(false);
141 } 126 }
142 127
143 /** 128 /**
144 * Repositions the image by translating it (without affecting the zoom level ). 129 * Repositions the image by translating it (without affecting the zoom level ).
145 *
146 * @param centerViewport Determines whether the viewport will be translated to the desired
147 * center position before being adjusted to fit the sc reen boundaries.
148 */ 130 */
149 public void repositionImage(boolean centerViewport) { 131 public void repositionImage() {
150 // The goal of the code below is to position the viewport as close to th e desired center 132 // The goal of the code below is to position the viewport as close to th e desired center
Lambros 2016/09/27 02:16:36 The phrase 'desired center' is how you've describe
joedow 2016/09/27 20:09:29 Acknowledged.
151 // position as possible whilst keeping as much of the desktop in view as possible. 133 // position as possible whilst keeping as much of the desktop in view as possible.
152 // To achieve these goals, we first position the desktop image at the de sired center 134 // To achieve these goals, we first position the desktop image at the de sired center
153 // point and then re-position it to maximize the viewable area. 135 // point and then re-position it to maximize the viewable area.
154 if (centerViewport) { 136 moveViewportToPoint(mViewportPosition);
Lambros 2016/09/27 02:16:37 This call modifies the transformation matrix so th
joedow 2016/09/27 20:09:28 Acknowledged.
155 // Map the current viewport position to screen coordinates. 137 translateImageToFitScreen();
Lambros 2016/09/27 02:16:37 But this call will modify the matrix *without* upd
joedow 2016/09/27 20:09:29 Acknowledged.
156 float[] viewportPosition = {mViewportPosition.x, mViewportPosition.y }; 138 }
157 mRenderData.transform.mapPoints(viewportPosition);
158 139
159 float viewportTransX = ((float) mRenderData.screenWidth / 2) - viewp ortPosition[0]; 140 /**
160 float viewportTransY = ((float) mRenderData.screenHeight / 2) - view portPosition[1]; 141 * Repositions the image by translating and zooming it, to keep the zoom lev el within sensible
161 142 * limits. The minimum zoom level is chosen to avoid black space around all 4 sides. The
162 // Translate so the viewport is displayed in the middle of the scree n. 143 * maximum zoom level is set arbitrarily, so that the user can zoom out agai n in a reasonable
163 mRenderData.transform.postTranslate(viewportTransX, viewportTransY); 144 * time, and to prevent arithmetic overflow problems from displaying the ima ge.
145 *
146 * @param centerOnCursor Determines whether the viewport will be translated to the desired
147 * center position before being adjusted to fit the sc reen boundaries.
148 */
149 public void repositionImageWithZoom(boolean centerOnCursor) {
150 // Avoid division by zero in case this gets called before the image size is initialized.
151 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) {
152 return;
164 } 153 }
165 154
155 // Zoom out if the zoom level is too high.
156 float currentZoomLevel = mRenderData.transform.mapRadius(1.0f);
157 if (currentZoomLevel > MAX_ZOOM_FACTOR) {
158 mRenderData.transform.setScale(MAX_ZOOM_FACTOR, MAX_ZOOM_FACTOR);
159 }
160
161 // Get image size scaled to screen coordinates.
162 float[] imageSize = {mRenderData.imageWidth, mRenderData.imageHeight};
163 mRenderData.transform.mapVectors(imageSize);
164
165 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData .screenHeight) {
166 // Displayed image is too small in both directions, so apply the min imum zoom
167 // level needed to fit either the width or height.
168 float scale = Math.min((float) mRenderData.screenWidth / mRenderData .imageWidth,
169 (float) mRenderData.screenHeight / mRenderDat a.imageHeight);
170 mRenderData.transform.setScale(scale, scale);
171 }
172
173 if (centerOnCursor) {
174 moveViewportToPoint(mCursorPosition);
175 }
176
177 translateImageToFitScreen();
178
179 // Update our position members to reflect the new position of the image.
180 PointF newPosition;
181 if (centerOnCursor) {
182 newPosition = new PointF(mCursorPosition.x, mCursorPosition.y);
183 } else {
184 float screenCenterX = (float) mRenderData.screenWidth / 2;
185 float screenCenterY = (float) mRenderData.screenHeight / 2;
186 float[] mappedPoints = {screenCenterX, screenCenterY};
187 Matrix screenToImage = new Matrix();
188 mRenderData.transform.invert(screenToImage);
189 screenToImage.mapPoints(mappedPoints);
190 newPosition = new PointF(mappedPoints[0], mappedPoints[1]);
191 }
192 setViewportCenter(newPosition.x, newPosition.y);
193 }
194
195 /**
196 * Updates the given point such that it refers to a coordinate within the bo unds provided.
197 *
198 * @param point The point to adjust, the original object is modified.
199 * @param bounds The bounds used to constrain the point.
200 */
201 private void constrainPointToBounds(PointF point, RectF bounds) {
202 if (point.x < bounds.left) {
203 point.x = bounds.left;
204 } else if (point.x > bounds.right) {
205 point.x = bounds.right;
206 }
207
208 if (point.y < bounds.top) {
209 point.y = bounds.top;
210 } else if (point.y > bounds.bottom) {
211 point.y = bounds.bottom;
212 }
213 }
214
215 /** Returns a region which defines the set of valid cursor values in image s pace. */
216 private RectF getImageBounds() {
217 return new RectF(0, 0, mRenderData.imageWidth, mRenderData.imageHeight);
218 }
219
220 /** Returns a region which defines the set of valid viewport center values i n image space. */
221 private RectF getViewportBounds() {
Lambros 2016/09/27 02:16:37 IIUC, this is precisely the set of points for whic
joedow 2016/09/27 20:09:29 I was moving to a place where multiple transforms
222 float[] screenVectors = {
223 ((float) mRenderData.screenWidth / 2), ((float) mRenderData.scre enHeight / 2)};
224 Matrix screenToImage = new Matrix();
225 mRenderData.transform.invert(screenToImage);
226 screenToImage.mapVectors(screenVectors);
227 return new RectF(screenVectors[0], screenVectors[1],
228 mRenderData.imageWidth - screenVectors[0],
229 mRenderData.imageHeight - screenVectors[1]);
230 }
231
232 /** Centers the viewport on the passed in point. */
233 private void moveViewportToPoint(PointF point) {
234 // Map the current viewport position to screen coordinates.
235 float[] viewportPosition = {point.x, point.y};
236 mRenderData.transform.mapPoints(viewportPosition);
237
238 float viewportTransX = ((float) mRenderData.screenWidth / 2) - viewportP osition[0];
239 float viewportTransY = ((float) mRenderData.screenHeight / 2) - viewport Position[1];
240
241 // Translate so the viewport is displayed in the middle of the screen.
242 mRenderData.transform.postTranslate(viewportTransX, viewportTransY);
243 }
244
245 /** Repositions the image by translating it to maximize the amount of viewab le content. */
246 private void translateImageToFitScreen() {
166 // Get the coordinates of the desktop rectangle (top-left/bottom-right c orners) in 247 // Get the coordinates of the desktop rectangle (top-left/bottom-right c orners) in
167 // screen coordinates. Order is: left, top, right, bottom. 248 // screen coordinates. Order is: left, top, right, bottom.
168 RectF rectScreen = new RectF(0, 0, mRenderData.imageWidth, mRenderData.i mageHeight); 249 RectF rectScreen = new RectF(0, 0, mRenderData.imageWidth, mRenderData.i mageHeight);
169 mRenderData.transform.mapRect(rectScreen); 250 mRenderData.transform.mapRect(rectScreen);
170 251
171 float leftDelta = rectScreen.left; 252 float leftDelta = rectScreen.left;
172 float rightDelta = 253 float rightDelta = rectScreen.right - mRenderData.screenWidth;
173 rectScreen.right - mRenderData.screenWidth + mSystemUiOffsetPixe ls.right;
174 float topDelta = rectScreen.top; 254 float topDelta = rectScreen.top;
175 float bottomDelta = 255 float bottomDelta = rectScreen.bottom - mRenderData.screenHeight;
176 rectScreen.bottom - mRenderData.screenHeight + mSystemUiOffsetPi xels.bottom;
177 float xAdjust = 0; 256 float xAdjust = 0;
178 float yAdjust = 0; 257 float yAdjust = 0;
179 258
180 if (rectScreen.right - rectScreen.left < mRenderData.screenWidth) { 259 if (rectScreen.right - rectScreen.left < mRenderData.screenWidth) {
181 // Image is narrower than the screen, so center it. 260 // Image is narrower than the screen, so center it.
182 xAdjust = -(rightDelta + leftDelta) / 2; 261 xAdjust = -(rightDelta + leftDelta) / 2;
183 } else if (leftDelta > 0 && rightDelta > 0) { 262 } else if (leftDelta > 0 && rightDelta > 0) {
184 // Panning the image left will show more of it. 263 // Panning the image left will show more of it.
185 xAdjust = -Math.min(leftDelta, rightDelta); 264 xAdjust = -Math.min(leftDelta, rightDelta);
186 } else if (leftDelta < 0 && rightDelta < 0) { 265 } else if (leftDelta < 0 && rightDelta < 0) {
187 // Pan the image right. 266 // Pan the image right.
188 xAdjust = Math.min(-leftDelta, -rightDelta); 267 xAdjust = Math.min(-leftDelta, -rightDelta);
189 } 268 }
190 269
191 // Apply similar logic for yAdjust. 270 // Apply similar logic for yAdjust.
192 if (rectScreen.bottom - rectScreen.top < mRenderData.screenHeight) { 271 if (rectScreen.bottom - rectScreen.top < mRenderData.screenHeight) {
193 yAdjust = -(bottomDelta + topDelta) / 2; 272 yAdjust = -(bottomDelta + topDelta) / 2;
194 } else if (topDelta > 0 && bottomDelta > 0) { 273 } else if (topDelta > 0 && bottomDelta > 0) {
195 yAdjust = -Math.min(topDelta, bottomDelta); 274 yAdjust = -Math.min(topDelta, bottomDelta);
196 } else if (topDelta < 0 && bottomDelta < 0) { 275 } else if (topDelta < 0 && bottomDelta < 0) {
197 yAdjust = Math.min(-topDelta, -bottomDelta); 276 yAdjust = Math.min(-topDelta, -bottomDelta);
198 } 277 }
199 278
200 mRenderData.transform.postTranslate(xAdjust, yAdjust); 279 mRenderData.transform.postTranslate(xAdjust, yAdjust);
Lambros 2016/09/27 02:16:37 By actually transforming the matrix here, you brea
joedow 2016/09/27 20:09:29 Acknowledged.
201 280
202 mRenderStub.setTransformation(mRenderData.transform); 281 mRenderStub.setTransformation(mRenderData.transform);
203 } 282 }
204
205 /**
206 * Repositions the image by translating and zooming it, to keep the zoom lev el within sensible
207 * limits. The minimum zoom level is chosen to avoid black space around all 4 sides. The
208 * maximum zoom level is set arbitrarily, so that the user can zoom out agai n in a reasonable
209 * time, and to prevent arithmetic overflow problems from displaying the ima ge.
210 *
211 * @param centerViewport Determines whether the viewport will be translated to the desired
212 * center position before being adjusted to fit the sc reen boundaries.
213 */
214 public void repositionImageWithZoom(boolean centerViewport) {
215 // Avoid division by zero in case this gets called before the image size is initialized.
216 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) {
217 return;
218 }
219
220 // Zoom out if the zoom level is too high.
221 float currentZoomLevel = mRenderData.transform.mapRadius(1.0f);
222 if (currentZoomLevel > MAX_ZOOM_FACTOR) {
223 mRenderData.transform.setScale(MAX_ZOOM_FACTOR, MAX_ZOOM_FACTOR);
224 }
225
226 // Get image size scaled to screen coordinates.
227 float[] imageSize = {mRenderData.imageWidth, mRenderData.imageHeight};
228 mRenderData.transform.mapVectors(imageSize);
229
230 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData .screenHeight) {
231 // Displayed image is too small in both directions, so apply the min imum zoom
232 // level needed to fit either the width or height.
233 float scale = Math.min((float) mRenderData.screenWidth / mRenderData .imageWidth,
234 (float) mRenderData.screenHeight / mRenderDat a.imageHeight);
235 mRenderData.transform.setScale(scale, scale);
236 }
237
238 repositionImage(centerViewport);
239 }
240 } 283 }
OLDNEW
« no previous file with comments | « no previous file | remoting/android/java/src/org/chromium/chromoting/TouchInputHandler.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698