| 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.PointF; | 8 import android.graphics.PointF; |
| 9 import android.graphics.Rect; |
| 8 import android.graphics.RectF; | 10 import android.graphics.RectF; |
| 9 | 11 |
| 10 /** | 12 /** |
| 11 * This class is responsible for transforming the desktop image matrix. | 13 * This class is responsible for transforming the desktop image matrix. |
| 12 */ | 14 */ |
| 13 public class DesktopCanvas { | 15 public class DesktopCanvas { |
| 14 /** | 16 /** |
| 15 * Maximum allowed zoom level - see {@link #repositionImageWithZoom()}. | 17 * Maximum allowed zoom level - see {@link #repositionImageWithZoom()}. |
| 16 */ | 18 */ |
| 17 private static final float MAX_ZOOM_FACTOR = 100.0f; | 19 private static final float MAX_ZOOM_FACTOR = 100.0f; |
| 18 | 20 |
| 19 private final DesktopViewInterface mViewer; | 21 private final DesktopViewInterface mViewer; |
| 20 private final RenderData mRenderData; | 22 private final RenderData mRenderData; |
| 21 | 23 |
| 22 /** | 24 /** |
| 23 * Represents the desired center of the viewport. This value may not repres
ent the actual | 25 * Represents the desired center of the viewport. This value may not repres
ent the actual |
| 24 * center of the viewport as adjustments are made to ensure as much of the d
esktop is visible as | 26 * center of the viewport as adjustments are made to ensure as much of the d
esktop is visible as |
| 25 * possible. This value needs to be a pair of floats so the desktop image c
an be positioned | 27 * possible. This value needs to be a pair of floats so the desktop image c
an be positioned |
| 26 * with sub-pixel accuracy for smoother panning animations at high zoom leve
ls. | 28 * with sub-pixel accuracy for smoother panning animations at high zoom leve
ls. |
| 27 */ | 29 */ |
| 28 private PointF mViewportPosition = new PointF(); | 30 private PointF mViewportPosition = new PointF(); |
| 29 | 31 |
| 30 /** | 32 /** |
| 31 * Represents the amount of vertical space in pixels used by the soft input
device and | 33 * Represents the amount of space, in pixels, used by system UI. |
| 32 * accompanying system UI. | |
| 33 */ | 34 */ |
| 34 private int mInputMethodOffsetY = 0; | 35 private Rect mSystemUiOffsetPixels = new Rect(); |
| 35 | |
| 36 /** | |
| 37 * Represents the amount of horizontal space in pixels used by the soft inpu
t device and | |
| 38 * accompanying system UI. | |
| 39 */ | |
| 40 private int mInputMethodOffsetX = 0; | |
| 41 | 36 |
| 42 public DesktopCanvas(DesktopViewInterface viewer, RenderData renderData) { | 37 public DesktopCanvas(DesktopViewInterface viewer, RenderData renderData) { |
| 43 mViewer = viewer; | 38 mViewer = viewer; |
| 44 mRenderData = renderData; | 39 mRenderData = renderData; |
| 45 } | 40 } |
| 46 | 41 |
| 47 /** | 42 /** |
| 48 * Returns the desired center position of the viewport. Note that this may
not represent the | 43 * Shifts the viewport by the passed in deltas (in image coordinates). |
| 49 * true center of the viewport as other calculations are done to maximize th
e viewable area. | |
| 50 * | 44 * |
| 51 * @return A point representing the desired position of the viewport. | 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. |
| 52 */ | 50 */ |
| 53 public PointF getViewportPosition() { | 51 public PointF moveViewportCenter(boolean useScreenCenter, float deltaX, floa
t deltaY) { |
| 54 return new PointF(mViewportPosition.x, mViewportPosition.y); | 52 PointF viewportCenter; |
| 55 } | 53 synchronized (mRenderData) { |
| 54 RectF bounds = new RectF(0, 0, mRenderData.imageWidth, mRenderData.i
mageHeight); |
| 55 if (useScreenCenter) { |
| 56 viewportCenter = getTrueViewportCenter(); |
| 57 } else { |
| 58 viewportCenter = new PointF(mViewportPosition.x, mViewportPositi
on.y); |
| 59 } |
| 56 | 60 |
| 57 /** | 61 viewportCenter.offset(deltaX, deltaY); |
| 58 * Sets the desired center position of the viewport. | 62 if (viewportCenter.x < bounds.left) { |
| 59 * | 63 viewportCenter.x = bounds.left; |
| 60 * @param newX The new x coordinate value for the desired center position. | 64 } else if (viewportCenter.x > bounds.right) { |
| 61 * @param newY The new y coordinate value for the desired center position. | 65 viewportCenter.x = bounds.right; |
| 62 */ | 66 } |
| 63 public void setViewportPosition(float newX, float newY) { | |
| 64 mViewportPosition.set(newX, newY); | |
| 65 } | |
| 66 | 67 |
| 67 /** | 68 if (viewportCenter.y < bounds.top) { |
| 68 * Sets the offset values used to calculate the space used by the current so
ft input method. | 69 viewportCenter.y = bounds.top; |
| 69 * | 70 } else if (viewportCenter.y > bounds.bottom) { |
| 70 * @param offsetX The space used by the soft input method UI on the right ed
ge of the screen. | 71 viewportCenter.y = bounds.bottom; |
| 71 * @param offsetY The space used by the soft input method UI on the bottom e
dge of the screen. | 72 } |
| 72 */ | 73 |
| 73 public void setInputMethodOffsetValues(int offsetX, int offsetY) { | 74 mViewportPosition.set(viewportCenter); |
| 74 mInputMethodOffsetX = offsetX; | 75 } |
| 75 mInputMethodOffsetY = offsetY; | 76 |
| 77 return viewportCenter; |
| 76 } | 78 } |
| 77 | 79 |
| 78 /** | 80 /** |
| 79 * Returns the current size of the viewport. This size includes the offset
calculations for | 81 * Returns the current size of the viewport. This size includes the offset
calculations for |
| 80 * any visible Input Method UI. | 82 * any visible system UI. |
| 81 * | 83 * |
| 82 * @return A point representing the current size of the viewport. | 84 * @return A point representing the current size of the viewport. |
| 83 */ | 85 */ |
| 84 public PointF getViewportSize() { | 86 private PointF getViewportSize() { |
| 85 float adjustedScreenWidth, adjustedScreenHeight; | 87 float adjustedScreenWidth, adjustedScreenHeight; |
| 86 synchronized (mRenderData) { | 88 synchronized (mRenderData) { |
| 87 adjustedScreenWidth = mRenderData.screenWidth - mInputMethodOffsetX; | 89 adjustedScreenWidth = mRenderData.screenWidth - mSystemUiOffsetPixel
s.right; |
| 88 adjustedScreenHeight = mRenderData.screenHeight - mInputMethodOffset
Y; | 90 adjustedScreenHeight = mRenderData.screenHeight - mSystemUiOffsetPix
els.bottom; |
| 89 } | 91 } |
| 90 | 92 |
| 91 return new PointF(adjustedScreenWidth, adjustedScreenHeight); | 93 return new PointF(adjustedScreenWidth, adjustedScreenHeight); |
| 92 } | 94 } |
| 93 | 95 |
| 96 /** |
| 97 * Returns the true center position of the viewport (in image coordinates). |
| 98 * |
| 99 * @return A point representing the true center position of the viewport. |
| 100 */ |
| 101 private PointF getTrueViewportCenter() { |
| 102 synchronized (mRenderData) { |
| 103 PointF viewportSize = getViewportSize(); |
| 104 |
| 105 // Find the center point of the viewport on the screen. |
| 106 float[] viewportPosition = {((float) viewportSize.x / 2), ((float) v
iewportSize.y / 2)}; |
| 107 |
| 108 // Convert the screen position to an image position. |
| 109 Matrix screenToImage = new Matrix(); |
| 110 mRenderData.transform.invert(screenToImage); |
| 111 screenToImage.mapPoints(viewportPosition); |
| 112 return new PointF(viewportPosition[0], viewportPosition[1]); |
| 113 } |
| 114 } |
| 115 |
| 116 /** |
| 117 * Sets the offset values used to calculate the space used by system UI. |
| 118 * |
| 119 * @param left The space used by system UI on the left edge of the screen. |
| 120 * @param top The space used by system UI on the top edge of the screen. |
| 121 * @param right The space used by system UI on the right edge of the screen. |
| 122 * @param bottom The space used by system UI on the bottom edge of the scree
n. |
| 123 */ |
| 124 public void setSystemUiOffsetValues(int left, int top, int right, int bottom
) { |
| 125 synchronized (mRenderData) { |
| 126 mSystemUiOffsetPixels.set(left, top, right, bottom); |
| 127 } |
| 128 } |
| 129 |
| 94 /** Repositions the image by zooming it such that the image is displayed wit
hout borders. */ | 130 /** Repositions the image by zooming it such that the image is displayed wit
hout borders. */ |
| 95 public void resizeImageToFitScreen() { | 131 public void resizeImageToFitScreen() { |
| 96 synchronized (mRenderData) { | 132 synchronized (mRenderData) { |
| 97 // Protect against being called before the image has been initialize
d. | 133 // Protect against being called before the image has been initialize
d. |
| 98 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) { | 134 if (mRenderData.imageWidth == 0 || mRenderData.imageHeight == 0) { |
| 99 return; | 135 return; |
| 100 } | 136 } |
| 101 | 137 |
| 102 float widthRatio = (float) mRenderData.screenWidth / mRenderData.ima
geWidth; | 138 float widthRatio = (float) mRenderData.screenWidth / mRenderData.ima
geWidth; |
| 103 float heightRatio = (float) mRenderData.screenHeight / mRenderData.i
mageHeight; | 139 float heightRatio = (float) mRenderData.screenHeight / mRenderData.i
mageHeight; |
| 104 float screenToImageScale = Math.max(widthRatio, heightRatio); | 140 float screenToImageScale = Math.max(widthRatio, heightRatio); |
| 105 | 141 |
| 106 // If the image is smaller than the screen in either dimension, then
we want to scale it | 142 // If the image is smaller than the screen in either dimension, then
we want to scale it |
| 107 // up to fit both and fill the screen with the image of the remote d
esktop. | 143 // up to fit both and fill the screen with the image of the remote d
esktop. |
| 108 if (screenToImageScale > 1.0f) { | 144 if (screenToImageScale > 1.0f) { |
| 109 mRenderData.transform.setScale(screenToImageScale, screenToImage
Scale); | 145 mRenderData.transform.setScale(screenToImageScale, screenToImage
Scale); |
| 110 } | 146 } |
| 111 } | 147 } |
| 112 | 148 |
| 113 repositionImage(false); | 149 repositionImage(false); |
| 114 } | 150 } |
| 115 | 151 |
| 116 /** | 152 /** |
| 117 * Repositions the image by translating it (without affecting the zoom level
). | 153 * Repositions the image by translating it (without affecting the zoom level
). |
| 118 * | 154 * |
| 119 * @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 |
| 120 * center position before being adjusted to fit the sc
reen boundaries. | 156 * center position before being adjusted to fit the sc
reen boundaries. |
| 121 */ | 157 */ |
| 122 public void repositionImage(boolean centerViewport) { | 158 public void repositionImage(boolean centerViewport) { |
| 123 PointF adjustedViewportSize = getViewportSize(); | 159 PointF viewportSize = getViewportSize(); |
| 124 synchronized (mRenderData) { | 160 synchronized (mRenderData) { |
| 125 // The goal of the code below is to position the viewport as close t
o the desired center | 161 // The goal of the code below is to position the viewport as close t
o the desired center |
| 126 // position as possible whilst keeping as much of the desktop in vie
w as possible. | 162 // position as possible whilst keeping as much of the desktop in vie
w as possible. |
| 127 // To achieve these goals, we first position the desktop image at th
e desired center | 163 // To achieve these goals, we first position the desktop image at th
e desired center |
| 128 // point and then re-position it to maximize the viewable area. | 164 // point and then re-position it to maximize the viewable area. |
| 129 if (centerViewport) { | 165 if (centerViewport) { |
| 130 // Map the current viewport position to screen coordinates. | 166 // Map the current viewport position to screen coordinates. |
| 131 float[] viewportPosition = {mViewportPosition.x, mViewportPositi
on.y}; | 167 float[] viewportPosition = {mViewportPosition.x, mViewportPositi
on.y}; |
| 132 mRenderData.transform.mapPoints(viewportPosition); | 168 mRenderData.transform.mapPoints(viewportPosition); |
| 133 | 169 |
| 134 // Translate so the viewport is displayed in the middle of the s
creen. | 170 // Translate so the viewport is displayed in the middle of the s
creen. |
| 135 mRenderData.transform.postTranslate( | 171 mRenderData.transform.postTranslate( |
| 136 (float) adjustedViewportSize.x / 2 - viewportPosition[0]
, | 172 ((float) viewportSize.x / 2) - viewportPosition[0], |
| 137 (float) adjustedViewportSize.y / 2 - viewportPosition[1]
); | 173 ((float) viewportSize.y / 2) - viewportPosition[1]); |
| 138 } | 174 } |
| 139 | 175 |
| 140 // Get the coordinates of the desktop rectangle (top-left/bottom-rig
ht corners) in | 176 // Get the coordinates of the desktop rectangle (top-left/bottom-rig
ht corners) in |
| 141 // screen coordinates. Order is: left, top, right, bottom. | 177 // screen coordinates. Order is: left, top, right, bottom. |
| 142 RectF rectScreen = new RectF(0, 0, mRenderData.imageWidth, mRenderDa
ta.imageHeight); | 178 RectF rectScreen = new RectF(0, 0, mRenderData.imageWidth, mRenderDa
ta.imageHeight); |
| 143 mRenderData.transform.mapRect(rectScreen); | 179 mRenderData.transform.mapRect(rectScreen); |
| 144 | 180 |
| 145 float leftDelta = rectScreen.left; | 181 float leftDelta = rectScreen.left; |
| 146 float rightDelta = rectScreen.right - mRenderData.screenWidth + mInp
utMethodOffsetX; | 182 float rightDelta = |
| 183 rectScreen.right - mRenderData.screenWidth + mSystemUiOffset
Pixels.right; |
| 147 float topDelta = rectScreen.top; | 184 float topDelta = rectScreen.top; |
| 148 float bottomDelta = rectScreen.bottom - mRenderData.screenHeight + m
InputMethodOffsetY; | 185 float bottomDelta = |
| 186 rectScreen.bottom - mRenderData.screenHeight + mSystemUiOffs
etPixels.bottom; |
| 149 float xAdjust = 0; | 187 float xAdjust = 0; |
| 150 float yAdjust = 0; | 188 float yAdjust = 0; |
| 151 | 189 |
| 152 if (rectScreen.right - rectScreen.left < adjustedViewportSize.x) { | 190 if (rectScreen.right - rectScreen.left < viewportSize.x) { |
| 153 // Image is narrower than the screen, so center it. | 191 // Image is narrower than the screen, so center it. |
| 154 xAdjust = -(rightDelta + leftDelta) / 2; | 192 xAdjust = -(rightDelta + leftDelta) / 2; |
| 155 } else if (leftDelta > 0 && rightDelta > 0) { | 193 } else if (leftDelta > 0 && rightDelta > 0) { |
| 156 // Panning the image left will show more of it. | 194 // Panning the image left will show more of it. |
| 157 xAdjust = -Math.min(leftDelta, rightDelta); | 195 xAdjust = -Math.min(leftDelta, rightDelta); |
| 158 } else if (leftDelta < 0 && rightDelta < 0) { | 196 } else if (leftDelta < 0 && rightDelta < 0) { |
| 159 // Pan the image right. | 197 // Pan the image right. |
| 160 xAdjust = Math.min(-leftDelta, -rightDelta); | 198 xAdjust = Math.min(-leftDelta, -rightDelta); |
| 161 } | 199 } |
| 162 | 200 |
| 163 // Apply similar logic for yAdjust. | 201 // Apply similar logic for yAdjust. |
| 164 if (rectScreen.bottom - rectScreen.top < adjustedViewportSize.y) { | 202 if (rectScreen.bottom - rectScreen.top < viewportSize.y) { |
| 165 yAdjust = -(bottomDelta + topDelta) / 2; | 203 yAdjust = -(bottomDelta + topDelta) / 2; |
| 166 } else if (topDelta > 0 && bottomDelta > 0) { | 204 } else if (topDelta > 0 && bottomDelta > 0) { |
| 167 yAdjust = -Math.min(topDelta, bottomDelta); | 205 yAdjust = -Math.min(topDelta, bottomDelta); |
| 168 } else if (topDelta < 0 && bottomDelta < 0) { | 206 } else if (topDelta < 0 && bottomDelta < 0) { |
| 169 yAdjust = Math.min(-topDelta, -bottomDelta); | 207 yAdjust = Math.min(-topDelta, -bottomDelta); |
| 170 } | 208 } |
| 171 | 209 |
| 172 mRenderData.transform.postTranslate(xAdjust, yAdjust); | 210 mRenderData.transform.postTranslate(xAdjust, yAdjust); |
| 173 | 211 |
| 174 mViewer.transformationChanged(); | 212 mViewer.transformationChanged(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 // level needed to fit either the width or height. | 244 // level needed to fit either the width or height. |
| 207 float scale = Math.min((float) mRenderData.screenWidth / mRender
Data.imageWidth, | 245 float scale = Math.min((float) mRenderData.screenWidth / mRender
Data.imageWidth, |
| 208 (float) mRenderData.screenHeight / mRende
rData.imageHeight); | 246 (float) mRenderData.screenHeight / mRende
rData.imageHeight); |
| 209 mRenderData.transform.setScale(scale, scale); | 247 mRenderData.transform.setScale(scale, scale); |
| 210 } | 248 } |
| 211 } | 249 } |
| 212 | 250 |
| 213 repositionImage(centerViewport); | 251 repositionImage(centerViewport); |
| 214 } | 252 } |
| 215 } | 253 } |
| OLD | NEW |