OLD | NEW |
---|---|
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 #scaleAndRepositionImage()}. |
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 /** | |
22 * Used to smoothly reduce the amount of padding while the user is zooming. | |
23 */ | |
24 private static final float PADDING_REDUCTION_FACTOR = 0.85f; | |
25 | |
21 private final RenderStub mRenderStub; | 26 private final RenderStub mRenderStub; |
22 private final RenderData mRenderData; | 27 private final RenderData mRenderData; |
23 | 28 |
24 /** | 29 /** |
25 * Represents the actual center of the viewport. This value needs to be a p air of floats so the | 30 * Represents the actual center of the viewport in image space. This value needs to be a pair |
26 * desktop image can be positioned with sub-pixel accuracy for smoother pann ing animations at | 31 * of floats so the desktop image can be positioned with sub-pixel accuracy for smoother panning |
27 * high zoom levels. | 32 * animations at high zoom levels. |
28 */ | 33 */ |
29 private PointF mViewportPosition = new PointF(); | 34 private PointF mViewportPosition = new PointF(); |
Lambros
2016/10/04 22:06:35
Optional, not really part of this CL:
Is there any
joedow
2016/10/04 23:32:11
This was more important before I rewrote the posit
| |
30 | 35 |
31 /** | 36 /** |
32 * Represents the desired center of the viewport. This value may not repres ent the actual | 37 * Represents the desired center of the viewport in image space. This value may not represent |
Lambros
2016/10/04 22:06:35
Clarify that this position may extend beyond the b
joedow
2016/10/04 23:32:11
Done.
| |
33 * center of the viewport as adjustments are made to ensure as much of the d esktop is visible as | 38 * the actual center of the viewport as adjustments are made to ensure as mu ch of the desktop is |
34 * possible. This value needs to be a pair of floats so the desktop image c an be positioned | 39 * visible as possible. This value needs to be a pair of floats so the desk top image can be |
35 * with sub-pixel accuracy for smoother panning animations at high zoom leve ls. | 40 * positioned with sub-pixel accuracy for smoother panning animations at hig h zoom levels. |
36 */ | 41 */ |
37 private PointF mCursorPosition = new PointF(); | 42 private PointF mCursorPosition = new PointF(); |
38 | 43 |
39 /** | 44 /** |
40 * Represents the amount of space, in pixels, used by System UI. | 45 * Represents the amount of space, in pixels, used by System UI on each edge of the screen. |
41 */ | 46 */ |
42 private Rect mSystemUiOffsetPixels = new Rect(); | 47 private Rect mSystemUiScreenSize = new Rect(); |
Lambros
2016/10/04 22:06:35
Now you've renamed this to remove 'offset', maybe
joedow
2016/10/04 23:32:11
Acknowledged. Added TODO.
| |
48 | |
49 /** | |
50 * Represents the amount of padding, in screen pixels, added to each edge of the desktop image. | |
51 * This extra space allows the user to reveal portions of the desktop image which are obscured | |
52 * by System UI. | |
53 */ | |
54 private RectF mVisibleImagePadding = new RectF(); | |
Lambros
2016/10/04 22:06:35
optional:
Would be nice if you could remove this m
joedow
2016/10/04 23:32:11
Acknowledged.
| |
43 | 55 |
44 public DesktopCanvas(RenderStub renderStub, RenderData renderData) { | 56 public DesktopCanvas(RenderStub renderStub, RenderData renderData) { |
45 mRenderStub = renderStub; | 57 mRenderStub = renderStub; |
46 mRenderData = renderData; | 58 mRenderData = renderData; |
47 } | 59 } |
48 | 60 |
49 /** | 61 /** |
50 * Sets the desired center position of the viewport (a.k.a. the cursor posit ion) and ensures | 62 * Sets the desired center position of the viewport (a.k.a. the cursor posit ion) and ensures |
51 * the viewport is updated to include the cursor within it. | 63 * the viewport is updated to include the cursor within it. |
52 * | 64 * |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 | 109 |
98 /** | 110 /** |
99 * Sets the offset values used to calculate the space used by System UI. | 111 * Sets the offset values used to calculate the space used by System UI. |
100 * | 112 * |
101 * @param left The space used by System UI on the left edge of the screen. | 113 * @param left The space used by System UI on the left edge of the screen. |
102 * @param top The space used by System UI on the top edge of the screen. | 114 * @param top The space used by System UI on the top edge of the screen. |
103 * @param right The space used by System UI on the right edge of the screen. | 115 * @param right The space used by System UI on the right edge of the screen. |
104 * @param bottom The space used by System UI on the bottom edge of the scree n. | 116 * @param bottom The space used by System UI on the bottom edge of the scree n. |
105 */ | 117 */ |
106 public void setSystemUiOffsetValues(int left, int top, int right, int bottom ) { | 118 public void setSystemUiOffsetValues(int left, int top, int right, int bottom ) { |
107 mSystemUiOffsetPixels.set(left, top, right, bottom); | 119 mSystemUiScreenSize.set(left, top, right, bottom); |
108 } | 120 } |
109 | 121 |
110 /** Called to indicate that no System UI is visible. */ | 122 /** Called to indicate that no System UI is visible. */ |
111 public void clearSystemUiOffsets() { | 123 public void clearSystemUiOffsets() { |
112 mSystemUiOffsetPixels.setEmpty(); | 124 mSystemUiScreenSize.setEmpty(); |
113 } | 125 } |
114 | 126 |
115 /** Resizes the image by zooming it such that the image is displayed without borders. */ | 127 /** Resizes the image by zooming it such that the image is displayed without borders. */ |
116 public void resizeImageToFitScreen() { | 128 public void resizeImageToFitScreen() { |
117 // Protect against being called before the image has been initialized. | 129 // Protect against being called before the image has been initialized. |
118 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) { | 130 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) { |
119 return; | 131 return; |
120 } | 132 } |
121 | 133 |
122 float widthRatio = (float) mRenderData.screenWidth / mRenderData.imageWi dth; | 134 float widthRatio = (float) mRenderData.screenWidth / mRenderData.imageWi dth; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
162 mRenderData.transform.mapVectors(imageSize); | 174 mRenderData.transform.mapVectors(imageSize); |
163 | 175 |
164 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData .screenHeight) { | 176 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData .screenHeight) { |
165 // Displayed image is too small in both directions, so apply the min imum zoom | 177 // Displayed image is too small in both directions, so apply the min imum zoom |
166 // level needed to fit either the width or height. | 178 // level needed to fit either the width or height. |
167 float scale = Math.min((float) mRenderData.screenWidth / mRenderData .imageWidth, | 179 float scale = Math.min((float) mRenderData.screenWidth / mRenderData .imageWidth, |
168 (float) mRenderData.screenHeight / mRenderDat a.imageHeight); | 180 (float) mRenderData.screenHeight / mRenderDat a.imageHeight); |
169 mRenderData.transform.setScale(scale, scale); | 181 mRenderData.transform.setScale(scale, scale); |
170 } | 182 } |
171 | 183 |
184 // Trim the image padding if the user is zooming out. This prevents cas es where the image | |
185 // pops to the center when it reaches its minimum size. Note that we do not need to do | |
186 // anything when the user is zooming in as the canvas will expand and ab sorb the padding. | |
187 if (scaleFactor < 1.0f) { | |
188 mVisibleImagePadding.set(mVisibleImagePadding.left * PADDING_REDUCTI ON_FACTOR, | |
189 mVisibleImagePadding.top * PADDING_REDUCTION_FACTOR, | |
190 mVisibleImagePadding.right * PADDING_REDUCTION_FACTOR, | |
191 mVisibleImagePadding.bottom * PADDING_REDUCTION_FACTOR); | |
192 } | |
193 | |
172 if (centerOnCursor) { | 194 if (centerOnCursor) { |
173 setCursorPosition(mCursorPosition.x, mCursorPosition.y); | 195 setCursorPosition(mCursorPosition.x, mCursorPosition.y); |
174 } else { | 196 } else { |
175 // Find the new screen center (it was probably changed during the zo om operation) and | 197 // Find the new screen center (it was probably changed during the zo om operation) and |
176 // update the viewport and cursor. | 198 // update the viewport and cursor. |
177 float[] mappedPoints = { | 199 float[] mappedPoints = { |
178 ((float) mRenderData.screenWidth / 2), ((float) mRenderData. screenHeight / 2)}; | 200 ((float) mRenderData.screenWidth / 2), ((float) mRenderData. screenHeight / 2)}; |
179 Matrix screenToImage = new Matrix(); | 201 Matrix screenToImage = new Matrix(); |
180 mRenderData.transform.invert(screenToImage); | 202 mRenderData.transform.invert(screenToImage); |
181 screenToImage.mapPoints(mappedPoints); | 203 screenToImage.mapPoints(mappedPoints); |
182 // The cursor is mapped to the center of the viewport in this case. | 204 // The cursor is mapped to the center of the viewport in this case. |
183 setCursorPosition(mappedPoints[0], mappedPoints[1]); | 205 setCursorPosition(mappedPoints[0], mappedPoints[1]); |
184 } | 206 } |
185 } | 207 } |
186 | 208 |
187 /** | 209 /** |
188 * Repositions the image by translating it (without affecting the zoom level ). | 210 * Repositions the image by translating it (without affecting the zoom level ). |
189 */ | 211 */ |
190 private void repositionImage() { | 212 private void repositionImage() { |
191 // Map the current viewport position to screen coordinates and adjust th e image position. | 213 // Map the current viewport position to screen coordinates and adjust th e image position. |
192 float[] viewportPosition = {mViewportPosition.x, mViewportPosition.y}; | 214 float[] viewportPosition = {mViewportPosition.x, mViewportPosition.y}; |
193 mRenderData.transform.mapPoints(viewportPosition); | 215 mRenderData.transform.mapPoints(viewportPosition); |
194 | 216 |
195 float viewportTransX = ((float) mRenderData.screenWidth / 2) - viewportP osition[0]; | 217 float viewportTransX = ((float) mRenderData.screenWidth / 2) - viewportP osition[0]; |
196 float viewportTransY = ((float) mRenderData.screenHeight / 2) - viewport Position[1]; | 218 float viewportTransY = ((float) mRenderData.screenHeight / 2) - viewport Position[1]; |
197 | 219 |
198 // Translate the image so the viewport center is displayed in the middle of the screen. | 220 // Translate the image so the viewport center is displayed in the middle of the screen. |
199 mRenderData.transform.postTranslate(viewportTransX, viewportTransY); | 221 mRenderData.transform.postTranslate(viewportTransX, viewportTransY); |
200 | 222 |
223 updateVisibleImagePadding(); | |
224 | |
201 mRenderStub.setTransformation(mRenderData.transform); | 225 mRenderStub.setTransformation(mRenderData.transform); |
202 } | 226 } |
203 | 227 |
204 /** | 228 /** |
205 * Updates the given point such that it refers to a coordinate within the bo unds provided. | 229 * Updates the given point such that it refers to a coordinate within the bo unds provided. |
206 * | 230 * |
207 * @param point The point to adjust, the original object is modified. | 231 * @param point The point to adjust, the original object is modified. |
208 * @param bounds The bounds used to constrain the point. | 232 * @param bounds The bounds used to constrain the point. |
209 */ | 233 */ |
210 private void constrainPointToBounds(PointF point, RectF bounds) { | 234 private void constrainPointToBounds(PointF point, RectF bounds) { |
211 if (point.x < bounds.left) { | 235 if (point.x < bounds.left) { |
212 point.x = bounds.left; | 236 point.x = bounds.left; |
213 } else if (point.x > bounds.right) { | 237 } else if (point.x > bounds.right) { |
214 point.x = bounds.right; | 238 point.x = bounds.right; |
215 } | 239 } |
216 | 240 |
217 if (point.y < bounds.top) { | 241 if (point.y < bounds.top) { |
218 point.y = bounds.top; | 242 point.y = bounds.top; |
219 } else if (point.y > bounds.bottom) { | 243 } else if (point.y > bounds.bottom) { |
220 point.y = bounds.bottom; | 244 point.y = bounds.bottom; |
221 } | 245 } |
222 } | 246 } |
223 | 247 |
224 /** Returns a region which defines the set of valid cursor values in image s pace. */ | 248 /** Returns a region which defines the set of valid cursor positions in imag e space. */ |
225 private RectF getImageBounds() { | 249 private RectF getImageBounds() { |
226 return new RectF(0, 0, mRenderData.imageWidth, mRenderData.imageHeight); | 250 // The set of valid cursor positions includes any point on the image as well as the padding. |
251 // Padding is additional space added to the image which is the larger va lue of: | |
252 // - Potential overlap of the System UI and image content | |
253 // - Actual amount of padding already being used | |
254 // | |
255 // By expanding the area, we allow the user to move the cursor 'under' t he System UI which | |
256 // pulls the content out from under it and allows it to be visible. Onc e the System UI has | |
257 // been dismissed or changes size, we use the actual padding value inste ad which prevents | |
258 // the desktop image from 'snapping' back to pre-System UI state. | |
259 RectF systemUiOverlap = getSystemUiOverlap(); | |
260 float[] padding = {Math.max(mVisibleImagePadding.left, systemUiOverlap.l eft), | |
261 Math.max(mVisibleImagePadding.top, systemUiOverlap.top), | |
262 Math.max(mVisibleImagePadding.right, systemUiOverlap.right), | |
263 Math.max(mVisibleImagePadding.bottom, systemUiOverlap.bottom)}; | |
264 Matrix screenToImage = new Matrix(); | |
265 mRenderData.transform.invert(screenToImage); | |
266 screenToImage.mapVectors(padding); | |
267 | |
268 return new RectF(-padding[0], -padding[1], mRenderData.imageWidth + padd ing[2], | |
269 mRenderData.imageHeight + padding[3]); | |
227 } | 270 } |
228 | 271 |
229 /** Returns a region which defines the set of valid viewport center values i n image space. */ | 272 /** Returns a region which defines the set of valid viewport center values i n image space. */ |
230 private RectF getViewportBounds() { | 273 private RectF getViewportBounds() { |
231 float[] screenVectors = {(float) mRenderData.screenWidth, (float) mRende rData.screenHeight}; | 274 // The region of allowable viewport values is the imageBound rect, inset by the size of the |
275 // viewport itself. This prevent over and under panning of the viewport while still | |
Lambros
2016/10/04 22:06:35
prevents
joedow
2016/10/04 23:32:11
Done.
| |
276 // allowing the user to see and interact with all pixels one the desktop image. | |
232 Matrix screenToImage = new Matrix(); | 277 Matrix screenToImage = new Matrix(); |
233 mRenderData.transform.invert(screenToImage); | 278 mRenderData.transform.invert(screenToImage); |
279 | |
280 float[] screenVectors = {(float) mRenderData.screenWidth, (float) mRende rData.screenHeight}; | |
234 screenToImage.mapVectors(screenVectors); | 281 screenToImage.mapVectors(screenVectors); |
235 | 282 |
236 float xAdjust = 0.0f; | 283 PointF letterboxPadding = getLetterboxPadding(); |
237 if (mRenderData.imageWidth < screenVectors[0]) { | 284 float[] letterboxPaddingVectors = {letterboxPadding.x, letterboxPadding. y}; |
238 // Image is narrower than the screen, so adjust the bounds to center it. | 285 screenToImage.mapVectors(letterboxPaddingVectors); |
239 xAdjust = (screenVectors[0] - mRenderData.imageWidth) / 2.0f; | |
240 } | |
241 | |
242 float yAdjust = 0.0f; | |
243 if (mRenderData.imageHeight < screenVectors[1]) { | |
244 // Image is shorter than the screen, so adjust the bounds to center it. | |
245 yAdjust = (screenVectors[1] - mRenderData.imageHeight) / 2.0f; | |
246 } | |
247 | 286 |
248 // screenCenter values are 1/2 of a particular screen dimension mapped t o image space. | 287 // screenCenter values are 1/2 of a particular screen dimension mapped t o image space. |
249 float screenCenterX = screenVectors[0] / 2.0f; | 288 float screenCenterX = (screenVectors[0] / 2.0f) - letterboxPaddingVector s[0]; |
250 float screenCenterY = screenVectors[1] / 2.0f; | 289 float screenCenterY = (screenVectors[1] / 2.0f) - letterboxPaddingVector s[1]; |
251 return new RectF(screenCenterX - xAdjust, screenCenterY - yAdjust, | 290 RectF imageBounds = getImageBounds(); |
252 mRenderData.imageWidth - screenCenterX + xAdjust, | 291 imageBounds.inset(screenCenterX, screenCenterY); |
253 mRenderData.imageHeight - screenCenterY + yAdjust); | 292 return imageBounds; |
293 } | |
294 | |
295 /** | |
296 * Provides the amount of padding needed to center the image content on the screen. | |
297 */ | |
298 private PointF getLetterboxPadding() { | |
299 float[] imageVectors = {mRenderData.imageWidth, mRenderData.imageHeight} ; | |
300 mRenderData.transform.mapVectors(imageVectors); | |
301 | |
302 // We want to letterbox when the image is smaller than the screen in a s pecific dimension. | |
303 // Since we center the image, split the difference so it is equally dist ributed. | |
304 float widthAdjust = | |
305 Math.max(((float) mRenderData.screenWidth - imageVectors[0]) / 2 .0f, 0.0f); | |
306 float heightAdjust = | |
307 Math.max(((float) mRenderData.screenHeight - imageVectors[1]) / 2.0f, 0.0f); | |
308 | |
309 return new PointF(widthAdjust, heightAdjust); | |
310 } | |
311 | |
312 /** | |
313 * Returns the amount of System UI along each edge of the screen which could overlap the remote | |
314 * desktop image below it. This is the maximum amount that could overlap, n ot the actual value. | |
315 */ | |
316 private RectF getSystemUiOverlap() { | |
317 // letterBox padding represents the space added to the image to center i t on the screen. | |
318 // Since it does not contain any interactable UI, we ignore it when calc ulating the overlap | |
319 // between the System UI and the remote desktop image. | |
320 // Note: Ignore negative padding (clamp to 0) since that means no overla p exists. | |
321 PointF letterboxPadding = getLetterboxPadding(); | |
322 return new RectF(Math.max(mSystemUiScreenSize.left - letterboxPadding.x, 0.0f), | |
323 Math.max(mSystemUiScreenSize.top - letterboxPadding.y, 0.0f), | |
324 Math.max(mSystemUiScreenSize.right - letterboxPadding.x, 0.0f), | |
325 Math.max(mSystemUiScreenSize.bottom - letterboxPadding.y, 0.0f)) ; | |
326 } | |
327 | |
328 /** | |
329 * Calculates the amount of padding visible on each edge of the desktop imag e. | |
330 */ | |
331 private void updateVisibleImagePadding() { | |
332 PointF letterboxPadding = getLetterboxPadding(); | |
333 float[] imagePoints = {0.0f, 0.0f, mRenderData.imageWidth, mRenderData.i mageHeight}; | |
334 mRenderData.transform.mapPoints(imagePoints); | |
335 | |
336 mVisibleImagePadding.set(Math.max(imagePoints[0] - letterboxPadding.x, 0 .0f), | |
337 Math.max(imagePoints[1] - letterboxPadding.y, 0.0f), | |
338 Math.max(mRenderData.screenWidth - imagePoints[2] - letterboxPad ding.x, 0.0f), | |
339 Math.max(mRenderData.screenHeight - imagePoints[3] - letterboxPa dding.y, 0.0f)); | |
254 } | 340 } |
255 } | 341 } |
OLD | NEW |