| 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; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 * Shifts the viewport by the passed in deltas (in image coordinates). | 43 * Shifts the viewport by the passed in deltas (in image coordinates). |
| 44 * | 44 * |
| 45 * @param useScreenCenter Determines whether to use the desired viewport pos
ition or the actual | 45 * @param useScreenCenter Determines whether to use the desired viewport pos
ition or the actual |
| 46 * center of the screen for positioning. | 46 * center of the screen for positioning. |
| 47 * @param deltaX The distance (in image coordinates) to move the viewport al
ong the x-axis. | 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. | 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. | 49 * @return A point representing the new center position of the viewport. |
| 50 */ | 50 */ |
| 51 public PointF moveViewportCenter(boolean useScreenCenter, float deltaX, floa
t deltaY) { | 51 public PointF moveViewportCenter(boolean useScreenCenter, float deltaX, floa
t deltaY) { |
| 52 PointF viewportCenter; | 52 PointF viewportCenter; |
| 53 synchronized (mRenderData) { | 53 if (useScreenCenter) { |
| 54 RectF bounds = new RectF(0, 0, mRenderData.imageWidth, mRenderData.i
mageHeight); | 54 viewportCenter = getTrueViewportCenter(); |
| 55 if (useScreenCenter) { | 55 } else { |
| 56 viewportCenter = getTrueViewportCenter(); | 56 viewportCenter = new PointF(mViewportPosition.x, mViewportPosition.y
); |
| 57 } else { | 57 } |
| 58 viewportCenter = new PointF(mViewportPosition.x, mViewportPositi
on.y); | 58 viewportCenter.offset(deltaX, deltaY); |
| 59 } | |
| 60 | 59 |
| 61 viewportCenter.offset(deltaX, deltaY); | 60 RectF bounds = new RectF(0, 0, mRenderData.imageWidth, mRenderData.image
Height); |
| 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 | 61 |
| 68 if (viewportCenter.y < bounds.top) { | 62 if (viewportCenter.x < bounds.left) { |
| 69 viewportCenter.y = bounds.top; | 63 viewportCenter.x = bounds.left; |
| 70 } else if (viewportCenter.y > bounds.bottom) { | 64 } else if (viewportCenter.x > bounds.right) { |
| 71 viewportCenter.y = bounds.bottom; | 65 viewportCenter.x = bounds.right; |
| 72 } | 66 } |
| 73 | 67 |
| 74 mViewportPosition.set(viewportCenter); | 68 if (viewportCenter.y < bounds.top) { |
| 69 viewportCenter.y = bounds.top; |
| 70 } else if (viewportCenter.y > bounds.bottom) { |
| 71 viewportCenter.y = bounds.bottom; |
| 75 } | 72 } |
| 76 | 73 |
| 74 mViewportPosition.set(viewportCenter); |
| 75 |
| 77 return viewportCenter; | 76 return viewportCenter; |
| 78 } | 77 } |
| 79 | 78 |
| 80 /** | 79 /** |
| 81 * Sets the desired center position of the viewport. | 80 * Sets the desired center position of the viewport. |
| 82 * | 81 * |
| 83 * @param newX The new x coordinate value for the desired center position. | 82 * @param newX The new x coordinate value for the desired center position. |
| 84 * @param newY The new y coordinate value for the desired center position. | 83 * @param newY The new y coordinate value for the desired center position. |
| 85 */ | 84 */ |
| 86 public void setViewportPosition(float newX, float newY) { | 85 public void setViewportPosition(float newX, float newY) { |
| 87 synchronized (mRenderData) { | 86 mViewportPosition.set(newX, newY); |
| 88 mViewportPosition.set(newX, newY); | |
| 89 } | |
| 90 } | 87 } |
| 91 | 88 |
| 92 /** | 89 /** |
| 93 * Returns the current size of the viewport. This size includes the offset
calculations for | 90 * Returns the current size of the viewport. This size includes the offset
calculations for |
| 94 * any visible system UI. | 91 * any visible system UI. |
| 95 * | 92 * |
| 96 * @return A point representing the current size of the viewport. | 93 * @return A point representing the current size of the viewport. |
| 97 */ | 94 */ |
| 98 private PointF getViewportSize() { | 95 private PointF getViewportSize() { |
| 99 float adjustedScreenWidth, adjustedScreenHeight; | 96 float adjustedScreenWidth = mRenderData.screenWidth - mSystemUiOffsetPix
els.right; |
| 100 synchronized (mRenderData) { | 97 float adjustedScreenHeight = mRenderData.screenHeight - mSystemUiOffsetP
ixels.bottom; |
| 101 adjustedScreenWidth = mRenderData.screenWidth - mSystemUiOffsetPixel
s.right; | |
| 102 adjustedScreenHeight = mRenderData.screenHeight - mSystemUiOffsetPix
els.bottom; | |
| 103 } | |
| 104 | 98 |
| 105 return new PointF(adjustedScreenWidth, adjustedScreenHeight); | 99 return new PointF(adjustedScreenWidth, adjustedScreenHeight); |
| 106 } | 100 } |
| 107 | 101 |
| 108 /** | 102 /** |
| 109 * Returns the true center position of the viewport (in image coordinates). | 103 * Returns the true center position of the viewport (in image coordinates). |
| 110 * | 104 * |
| 111 * @return A point representing the true center position of the viewport. | 105 * @return A point representing the true center position of the viewport. |
| 112 */ | 106 */ |
| 113 private PointF getTrueViewportCenter() { | 107 private PointF getTrueViewportCenter() { |
| 114 synchronized (mRenderData) { | 108 PointF viewportSize = getViewportSize(); |
| 115 PointF viewportSize = getViewportSize(); | |
| 116 | 109 |
| 117 // Find the center point of the viewport on the screen. | 110 // Find the center point of the viewport on the screen. |
| 118 float[] viewportPosition = {((float) viewportSize.x / 2), ((float) v
iewportSize.y / 2)}; | 111 float[] viewportPosition = {((float) viewportSize.x / 2), ((float) viewp
ortSize.y / 2)}; |
| 119 | 112 |
| 120 // Convert the screen position to an image position. | 113 // Convert the screen position to an image position. |
| 121 Matrix screenToImage = new Matrix(); | 114 Matrix screenToImage = new Matrix(); |
| 122 mRenderData.transform.invert(screenToImage); | 115 mRenderData.transform.invert(screenToImage); |
| 123 screenToImage.mapPoints(viewportPosition); | 116 screenToImage.mapPoints(viewportPosition); |
| 124 return new PointF(viewportPosition[0], viewportPosition[1]); | 117 return new PointF(viewportPosition[0], viewportPosition[1]); |
| 125 } | |
| 126 } | 118 } |
| 127 | 119 |
| 128 /** | 120 /** |
| 129 * Sets the offset values used to calculate the space used by system UI. | 121 * Sets the offset values used to calculate the space used by system UI. |
| 130 * | 122 * |
| 131 * @param left The space used by system UI on the left edge of the screen. | 123 * @param left The space used by system UI on the left edge of the screen. |
| 132 * @param top The space used by system UI on the top edge of the screen. | 124 * @param top The space used by system UI on the top edge of the screen. |
| 133 * @param right The space used by system UI on the right edge of the screen. | 125 * @param right The space used by system UI on the right edge of the screen. |
| 134 * @param bottom The space used by system UI on the bottom edge of the scree
n. | 126 * @param bottom The space used by system UI on the bottom edge of the scree
n. |
| 135 */ | 127 */ |
| 136 public void setSystemUiOffsetValues(int left, int top, int right, int bottom
) { | 128 public void setSystemUiOffsetValues(int left, int top, int right, int bottom
) { |
| 137 synchronized (mRenderData) { | 129 mSystemUiOffsetPixels.set(left, top, right, bottom); |
| 138 mSystemUiOffsetPixels.set(left, top, right, bottom); | |
| 139 } | |
| 140 } | 130 } |
| 141 | 131 |
| 142 /** Repositions the image by zooming it such that the image is displayed wit
hout borders. */ | 132 /** Repositions the image by zooming it such that the image is displayed wit
hout borders. */ |
| 143 public void resizeImageToFitScreen() { | 133 public void resizeImageToFitScreen() { |
| 144 synchronized (mRenderData) { | 134 // Protect against being called before the image has been initialized. |
| 145 // Protect against being called before the image has been initialize
d. | 135 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) { |
| 146 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) { | 136 return; |
| 147 return; | 137 } |
| 148 } | |
| 149 | 138 |
| 150 float widthRatio = (float) mRenderData.screenWidth / mRenderData.ima
geWidth; | 139 float widthRatio = (float) mRenderData.screenWidth / mRenderData.imageWi
dth; |
| 151 float heightRatio = (float) mRenderData.screenHeight / mRenderData.i
mageHeight; | 140 float heightRatio = (float) mRenderData.screenHeight / mRenderData.image
Height; |
| 152 float screenToImageScale = Math.max(widthRatio, heightRatio); | 141 float screenToImageScale = Math.max(widthRatio, heightRatio); |
| 153 | 142 |
| 154 // If the image is smaller than the screen in either dimension, then
we want to scale it | 143 // If the image is smaller than the screen in either dimension, then we
want to scale it |
| 155 // up to fit both and fill the screen with the image of the remote d
esktop. | 144 // up to fit both and fill the screen with the image of the remote deskt
op. |
| 156 if (screenToImageScale > 1.0f) { | 145 if (screenToImageScale > 1.0f) { |
| 157 mRenderData.transform.setScale(screenToImageScale, screenToImage
Scale); | 146 mRenderData.transform.setScale(screenToImageScale, screenToImageScal
e); |
| 158 } | |
| 159 } | 147 } |
| 160 | 148 |
| 161 repositionImage(false); | 149 repositionImage(false); |
| 162 } | 150 } |
| 163 | 151 |
| 164 /** | 152 /** |
| 165 * Repositions the image by translating it (without affecting the zoom level
). | 153 * Repositions the image by translating it (without affecting the zoom level
). |
| 166 * | 154 * |
| 167 * @param centerViewport Determines whether the viewport will be translated
to the desired | 155 * @param centerViewport Determines whether the viewport will be translated
to the desired |
| 168 * center position before being adjusted to fit the sc
reen boundaries. | 156 * center position before being adjusted to fit the sc
reen boundaries. |
| 169 */ | 157 */ |
| 170 public void repositionImage(boolean centerViewport) { | 158 public void repositionImage(boolean centerViewport) { |
| 171 PointF viewportSize = getViewportSize(); | 159 PointF viewportSize = getViewportSize(); |
| 172 synchronized (mRenderData) { | 160 // The goal of the code below is to position the viewport as close to th
e desired center |
| 173 // The goal of the code below is to position the viewport as close t
o the desired center | 161 // position as possible whilst keeping as much of the desktop in view as
possible. |
| 174 // position as possible whilst keeping as much of the desktop in vie
w as possible. | 162 // To achieve these goals, we first position the desktop image at the de
sired center |
| 175 // To achieve these goals, we first position the desktop image at th
e desired center | 163 // point and then re-position it to maximize the viewable area. |
| 176 // point and then re-position it to maximize the viewable area. | 164 if (centerViewport) { |
| 177 if (centerViewport) { | 165 // Map the current viewport position to screen coordinates. |
| 178 // Map the current viewport position to screen coordinates. | 166 float[] viewportPosition = {mViewportPosition.x, mViewportPosition.y
}; |
| 179 float[] viewportPosition = {mViewportPosition.x, mViewportPositi
on.y}; | 167 mRenderData.transform.mapPoints(viewportPosition); |
| 180 mRenderData.transform.mapPoints(viewportPosition); | |
| 181 | 168 |
| 182 // Translate so the viewport is displayed in the middle of the s
creen. | 169 // Translate so the viewport is displayed in the middle of the scree
n. |
| 183 mRenderData.transform.postTranslate( | 170 mRenderData.transform.postTranslate( |
| 184 ((float) viewportSize.x / 2) - viewportPosition[0], | 171 ((float) viewportSize.x / 2) - viewportPosition[0], |
| 185 ((float) viewportSize.y / 2) - viewportPosition[1]); | 172 ((float) viewportSize.y / 2) - viewportPosition[1]); |
| 186 } | 173 } |
| 187 | 174 |
| 188 // Get the coordinates of the desktop rectangle (top-left/bottom-rig
ht corners) in | 175 // Get the coordinates of the desktop rectangle (top-left/bottom-right c
orners) in |
| 189 // screen coordinates. Order is: left, top, right, bottom. | 176 // screen coordinates. Order is: left, top, right, bottom. |
| 190 RectF rectScreen = new RectF(0, 0, mRenderData.imageWidth, mRenderDa
ta.imageHeight); | 177 RectF rectScreen = new RectF(0, 0, mRenderData.imageWidth, mRenderData.i
mageHeight); |
| 191 mRenderData.transform.mapRect(rectScreen); | 178 mRenderData.transform.mapRect(rectScreen); |
| 192 | 179 |
| 193 float leftDelta = rectScreen.left; | 180 float leftDelta = rectScreen.left; |
| 194 float rightDelta = | 181 float rightDelta = |
| 195 rectScreen.right - mRenderData.screenWidth + mSystemUiOffset
Pixels.right; | 182 rectScreen.right - mRenderData.screenWidth + mSystemUiOffsetPixe
ls.right; |
| 196 float topDelta = rectScreen.top; | 183 float topDelta = rectScreen.top; |
| 197 float bottomDelta = | 184 float bottomDelta = |
| 198 rectScreen.bottom - mRenderData.screenHeight + mSystemUiOffs
etPixels.bottom; | 185 rectScreen.bottom - mRenderData.screenHeight + mSystemUiOffsetPi
xels.bottom; |
| 199 float xAdjust = 0; | 186 float xAdjust = 0; |
| 200 float yAdjust = 0; | 187 float yAdjust = 0; |
| 201 | 188 |
| 202 if (rectScreen.right - rectScreen.left < viewportSize.x) { | 189 if (rectScreen.right - rectScreen.left < viewportSize.x) { |
| 203 // Image is narrower than the screen, so center it. | 190 // Image is narrower than the screen, so center it. |
| 204 xAdjust = -(rightDelta + leftDelta) / 2; | 191 xAdjust = -(rightDelta + leftDelta) / 2; |
| 205 } else if (leftDelta > 0 && rightDelta > 0) { | 192 } else if (leftDelta > 0 && rightDelta > 0) { |
| 206 // Panning the image left will show more of it. | 193 // Panning the image left will show more of it. |
| 207 xAdjust = -Math.min(leftDelta, rightDelta); | 194 xAdjust = -Math.min(leftDelta, rightDelta); |
| 208 } else if (leftDelta < 0 && rightDelta < 0) { | 195 } else if (leftDelta < 0 && rightDelta < 0) { |
| 209 // Pan the image right. | 196 // Pan the image right. |
| 210 xAdjust = Math.min(-leftDelta, -rightDelta); | 197 xAdjust = Math.min(-leftDelta, -rightDelta); |
| 211 } | 198 } |
| 212 | 199 |
| 213 // Apply similar logic for yAdjust. | 200 // Apply similar logic for yAdjust. |
| 214 if (rectScreen.bottom - rectScreen.top < viewportSize.y) { | 201 if (rectScreen.bottom - rectScreen.top < viewportSize.y) { |
| 215 yAdjust = -(bottomDelta + topDelta) / 2; | 202 yAdjust = -(bottomDelta + topDelta) / 2; |
| 216 } else if (topDelta > 0 && bottomDelta > 0) { | 203 } else if (topDelta > 0 && bottomDelta > 0) { |
| 217 yAdjust = -Math.min(topDelta, bottomDelta); | 204 yAdjust = -Math.min(topDelta, bottomDelta); |
| 218 } else if (topDelta < 0 && bottomDelta < 0) { | 205 } else if (topDelta < 0 && bottomDelta < 0) { |
| 219 yAdjust = Math.min(-topDelta, -bottomDelta); | 206 yAdjust = Math.min(-topDelta, -bottomDelta); |
| 220 } | 207 } |
| 221 | 208 |
| 222 mRenderData.transform.postTranslate(xAdjust, yAdjust); | 209 mRenderData.transform.postTranslate(xAdjust, yAdjust); |
| 223 | 210 |
| 224 mViewer.transformationChanged(); | 211 mViewer.transformationChanged(); |
| 225 } | |
| 226 } | 212 } |
| 227 | 213 |
| 228 /** | 214 /** |
| 229 * Repositions the image by translating and zooming it, to keep the zoom lev
el within sensible | 215 * Repositions the image by translating and zooming it, to keep the zoom lev
el within sensible |
| 230 * limits. The minimum zoom level is chosen to avoid black space around all
4 sides. The | 216 * limits. The minimum zoom level is chosen to avoid black space around all
4 sides. The |
| 231 * maximum zoom level is set arbitrarily, so that the user can zoom out agai
n in a reasonable | 217 * maximum zoom level is set arbitrarily, so that the user can zoom out agai
n in a reasonable |
| 232 * time, and to prevent arithmetic overflow problems from displaying the ima
ge. | 218 * time, and to prevent arithmetic overflow problems from displaying the ima
ge. |
| 233 * | 219 * |
| 234 * @param centerViewport Determines whether the viewport will be translated
to the desired | 220 * @param centerViewport Determines whether the viewport will be translated
to the desired |
| 235 * center position before being adjusted to fit the sc
reen boundaries. | 221 * center position before being adjusted to fit the sc
reen boundaries. |
| 236 */ | 222 */ |
| 237 public void repositionImageWithZoom(boolean centerViewport) { | 223 public void repositionImageWithZoom(boolean centerViewport) { |
| 238 synchronized (mRenderData) { | 224 // Avoid division by zero in case this gets called before the image size
is initialized. |
| 239 // Avoid division by zero in case this gets called before the image
size is initialized. | 225 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) { |
| 240 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) { | 226 return; |
| 241 return; | 227 } |
| 242 } | |
| 243 | 228 |
| 244 // Zoom out if the zoom level is too high. | 229 // Zoom out if the zoom level is too high. |
| 245 float currentZoomLevel = mRenderData.transform.mapRadius(1.0f); | 230 float currentZoomLevel = mRenderData.transform.mapRadius(1.0f); |
| 246 if (currentZoomLevel > MAX_ZOOM_FACTOR) { | 231 if (currentZoomLevel > MAX_ZOOM_FACTOR) { |
| 247 mRenderData.transform.setScale(MAX_ZOOM_FACTOR, MAX_ZOOM_FACTOR)
; | 232 mRenderData.transform.setScale(MAX_ZOOM_FACTOR, MAX_ZOOM_FACTOR); |
| 248 } | 233 } |
| 249 | 234 |
| 250 // Get image size scaled to screen coordinates. | 235 // Get image size scaled to screen coordinates. |
| 251 float[] imageSize = {mRenderData.imageWidth, mRenderData.imageHeight
}; | 236 float[] imageSize = {mRenderData.imageWidth, mRenderData.imageHeight}; |
| 252 mRenderData.transform.mapVectors(imageSize); | 237 mRenderData.transform.mapVectors(imageSize); |
| 253 | 238 |
| 254 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRender
Data.screenHeight) { | 239 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData
.screenHeight) { |
| 255 // Displayed image is too small in both directions, so apply the
minimum zoom | 240 // Displayed image is too small in both directions, so apply the min
imum zoom |
| 256 // level needed to fit either the width or height. | 241 // level needed to fit either the width or height. |
| 257 float scale = Math.min((float) mRenderData.screenWidth / mRender
Data.imageWidth, | 242 float scale = Math.min((float) mRenderData.screenWidth / mRenderData
.imageWidth, |
| 258 (float) mRenderData.screenHeight / mRende
rData.imageHeight); | 243 (float) mRenderData.screenHeight / mRenderDat
a.imageHeight); |
| 259 mRenderData.transform.setScale(scale, scale); | 244 mRenderData.transform.setScale(scale, scale); |
| 260 } | |
| 261 } | 245 } |
| 262 | 246 |
| 263 repositionImage(centerViewport); | 247 repositionImage(centerViewport); |
| 264 } | 248 } |
| 265 } | 249 } |
| OLD | NEW |