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