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

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

Issue 2375113003: Allow Desktop Canvas to be scrolled out from under System UI. (Closed)
Patch Set: Adding comment block and addressing feedback 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 | no next file » | 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 *
15 * The transformation aspect is pretty simple, however the logic behind it is co mplex enough to
16 * warrant a longer chunk of comments to explain how that is accomplished.
17 *
18 * ===== Coordinate Systems =====
19 * First, there are two coordinate spaces at play here, screen space and image s pace, which map to
20 * coordinates on the device's screen and to the image used to display the remot e desktop
21 * respectively. We can convert from image coordinates to screen coordinates by using the transform
22 * matrix held by |mRenderData| and convert from screen coordinates to image coo rdinates using the
23 * inverse of that matrix.
24 *
25 * For consistency, position (viewport and cursor) member variables store paddin g in image space as
26 * do the internal methods which modify them (unless otherwise noted).
27 *
28 *
29 * ===== Viewport Concept =====
30 * Since the image used to display the remote desktop can be zoomed and panned s uch that only a
31 * portion of it is displayed on screen, this class defines that viewable area a s the "viewport".
32 * A goal of this class is to ensure the viewport contains the maximum amount of image pixels as it
33 * can. Thus it defines a subset of valid positions which map to the image, thes e are called
34 * boundaries or bounds. When a caller shifts the viewport, the new coordinate is checked to ensure
35 * it lies within the acceptable set of positions and is clamped to that viewabl e region if not.
36 * The viewport is tracked and bound by its center position.
37 *
38 * As an example, let's say the image is height 1000px and the screen height is 800 (both in screen
39 * coordinates). The viewport center would be located at 400px in this case and the viewport bounds
40 * would range from 400px to 600px. At 400px, the top of the image would align with the top of the
41 * screen and at 600px, the bottom of the image would align with the bottom of t he screen.
42 *
43 *
44 * ===== Cursor Position and Desired Viewport Concept =====
45 * Moving the viewport position is simple and works well for direct input method s, such as Touch,
46 * however indirect methods, such as Trackpad mode, requires tracking of another position. This
47 * second position can be thought of as the 'desired' viewport position and coin cides with the
48 * cursor position. It is called the desired position because it is the origina l position of the
49 * viewport before the bounds are applied. This class attempts to keep the desi red and actual
50 * viewport centers at the same coordinate, however when the user can move the c ursor to a position
51 * which is outside of the allowed coordinates for the viewport (i.e. the edge o f the screen).
52 * We can't move the viewport center to that location without breaking our goal of maximizing the
53 * viewable area of the screen, so instead we track the cursor position and begi n shifting the
54 * viewport again once the cursor moves back into the region of allowable viewpo rt positions.
55 *
56 *
57 * ===== Letterbox Padding =====
58 * One last note about the image and screen. When the image has been zoomed suc h that it is larger
59 * than the screen, we are free to move the viewport around as described above. However once the
60 * image is zoomed out such that one of the dimensions is smaller than the corre sponding screen
61 * dimension, we want to center the image within the viewport (and the screen). This is done by
62 * adding conceptual padding to the edges of the screen. As an example, when th e user zooms the
63 * image out and the height of the image (say 799px) drops below the screen heig ht (say 800px), we
64 * will add 0.5px to the top and bottom edges of the image in our position calcu lations. As the
65 * image height (in screen space) decreases (e.g. to 600px), the amount of paddi ng will increase.
66 * This ensures that the content is centered as the user zooms in and out. The same would occur
67 * if the image width (in screen space) dropped below the screen width with padd ing being added to
68 * the right and left edges of the image. This padding is referred to as "lette rbox" padding.
69 * Note that this padding is never applied to all four edges. The calculations used below allow one
70 * image dimension to decrease below the screen dimension but it prevents additi onal attempts to
71 * zoom out once the second image dimension matches the screen dimension.
Lambros 2016/10/03 23:04:10 I'm still struggling to understand this exact conc
joedow 2016/10/04 20:47:47 Discussed offline. I've simplifed the code a bit
72 *
73 *
74 * ===== Viewport and System UI Concepts =====
75 * System UI is defined as pixels displayed by the operating system. For us thi s boils down to four
76 * UI elements: status bar (located on the top edge of the screen), toolbar (loc ated below the
77 * status bar), navigation bar (located either at the bottom or right/left edge of the screen), and
78 * the soft input method (docked to bottom of the screen, possibly above the nav igation bar).
79 *
80 * Android has a mechanism to automatically resize the size of a UI View when Sy stem UI is displayed
81 * or changes size however this causes a jarring repositioning effect. We use t his mechanism in
82 * Pre-KitKat versions of Android as there isn't much of a choice. On KitKat an d later, we actually
83 * position the desktop image in a layer below the System UI so we can display t he image within the
84 * viewport in a consistent fashion and avoid those jarring reposition effects t hat occur on older
85 * OS versions. Though the experience is smoother, it also creates a new proble m which is how do
86 * users view and interact with remote UI elements on the image which are obscur ed by System UI.
87 *
88 * To address this problem, we allow the user to pan the remote image out from u nder the System UI.
89 * Our goal is to keep the viewport location consistent regardless of the System UI state whenever
90 * possible which leads to the following sections on padding and viewport positi on with System UI.
91 *
92 *
93 * ===== System UI Padding =====
94 * In order to allow the user to pan the image out from under System UI, we need to know how much
95 * space that UI occupies on the screen. This information is provided by the Vi ew whenever the size
96 * changes. This information is applied to the viewport boundaries to allow the user to move the
97 * viewport further in that direction than they could have previously.
98 *
99 * If we use the same sizes as before (image is 1000px and screen is 800px in sc reen coordinates),
100 * the allowable viewport position values in the y axis are 400px through 600px. If System UI is
101 * shown at the top and bottom of the screen (say 50px along both edges) then we need to adjust the
102 * viewport to allow panning past that UI, the updated range of allowed values i s 350px to 650px.
103 * This adjustment allows the user to pan the desktop image out from under any S ystem UI and fixes
104 * the original problem.
105 *
106 * There are two caveats though. The first is how to handle the case when the S ystem UI changes
107 * size or disappears. The second is a complication due to letterbox padding. We'll address each
108 * in their own sections.
109 *
110 *
111 * ===== System UI and Letterbox Padding Overlap =====
112 * If we did not account for letterbox padding when adjusting the viewport bound s, the behavior
113 * described in the System UI Padding section would fall apart when the image si ze (in screen space)
114 * decreased below the screen size. The effect would be that the user could pan the desktop image
115 * out from under the System UI (good) and then continue panning a distance defi ned by the amount of
116 * letterbox padding added to that edge. Functionally this is OK, but visually it looks broken. We
117 * address this problem by accounting for the overlap between the System UI and Letterbox padding.
118 *
119 * For this example, we will consider a single dimension (e.g. height) and assum e a screen size of
120 * 800px, an image size (once again in screen space) of 600px, letterbox padding on top and bottom
121 * edges of 100px, and System UI at the top and bottom of the screen at 50px eac h.
122 *
123 * Without the System UI, the viewport center would be locked to 400px (the actu al center of the
124 * image + letterbox padding). When the System UI was displayed, the range woul d be changed by 50px
125 * to 350px to 450px. This would allow the user to pan the image canvas by 50 p x in either
126 * direction. The problem here is that this panning is not useful as none of th e image is obscured
127 * by the System UI. Therefore we account for the letterbox padding and see tha t no scrolling is
128 * required and keep the viewport locked at 400px.
129 *
130 * The previous example showed an example interaction between a small System UI and the viewport
131 * bounds with letterbox padding, now let's consider a large System UI. In this example let's use
132 * a Soft Input Method UI which is 400 px tall and anchored to the bottom of the screen. Using the
133 * previous values (without letterboxing), the viewport range would be adjusted to 400px - 800px.
134 * This allows the image to be fully seen by the user, but includes a 100px blac k edge between the
135 * content and the System UI. What is needed is to account for the letterbox pa dding here as well.
136 * We subtract the padding (100px) from the allowable range and end up with 400p x - 700px. The
Lambros 2016/10/03 23:04:10 Shouldn't this be 500px - 700px ?
joedow 2016/10/04 20:47:47 Comment block removed.
137 * image is fully visible and no letterbox padding is displayed.
Lambros 2016/10/03 23:04:10 But the image isn't fully visible? It's 600px tall
joedow 2016/10/04 20:47:47 Comment block removed.
138 *
139 *
140 * ===== Image Padding and Ratcheting =====
141 * On to the problem of consistency. The sections above have solved the visibil ity problem, with
142 * the methods described above, the image can always be viewed and all coordinat es on the image can
143 * be interacted with using the cursor or touch. So now we move on to the probl em of handling the
144 * boundaries when the System UI changes.
145 *
146 * First a description of the behavior we desire in this scenario. Let's say th e user has panned
147 * their image out from under the status and toolbar (~150px). When those UI el ements are dismissed
148 * we have two options, immediately trim the padding used for it and snap the vi ewport back to its
149 * normal position or allow the viewport to remain until the extra padding is no longer required.
Lambros 2016/10/03 23:04:10 "extra padding"? The amount of padding is *less* w
joedow 2016/10/04 20:47:47 N/A Comment block removed.
150 * We have chosen the second approach.
151 *
152 * The idea is that after the System UI has been dismissed, we allow the viewpor t to remain as-is,
153 * but we don't want to keep this padding forever. The compromise is to 'eat' t he unneeded padding
154 * as the user pans the canvas, effectively creating a ratcheting effect.
155 *
156 * We accomplish this goal using a concept of image padding which tracks the act ual amount of
157 * padding in use for viewport calculations. In order to determine how much pad ding to use, we look
158 * at the adjusted System UI padding, current image padding, and the number of v isible pixels.
Lambros 2016/10/03 23:04:10 I don't understand "visible pixels" or the differe
joedow 2016/10/04 20:47:47 Comment block removed.
159 *
160 * More examples would be useful here. Instead of talking about a dimension, le t's focus on a
161 * single edge for this set of example scenarios. Everything starts with System UI being displayed,
162 * otherwise there is no need for padding. The System UI for this example has a lready been adjusted
Lambros 2016/10/03 23:04:10 "otherwise there is no need for padding" But lette
joedow 2016/10/04 20:47:47 Comment block removed.
163 * to account for letterbox padding and totals 50px.
164 * Note: The Visible Pixels are also adjusted to account for letterbox padding.
165 *
166 * Example: No padding is ever used in viewport calculations.
167 * The user pans the image but never moves the image out from under the System UI.
168 * Edge Calculation: System UI: 50px, Image Padding: 0px, Visible Pixels 0px
169 * Edge Padding result: 0px
170 * The System UI then disappears:
171 * Edge Calculation: System UI: 0px, Image Padding: 0px, Visible Pixels 0px
172 * Edge Padding result: 0px
173 *
174 * Example: Some padding is used in viewport calculations.
175 * The user pans the image halfway out from under the System UI.
176 * Edge Calculation: System UI: 50px, Image Padding: 0px, Visible Pixels 25px
177 * Edge Padding result: 25px
178 * The System UI then disappears (the viewport remains stationary):
179 * Edge Calculation: System UI: 0px, Image Padding: 25px, Visible Pixels 25px
180 * Edge Padding result: 25px
181 * The user pans away from the edge a bit (say 10px):
182 * Edge Calculation: System UI: 0px, Image Padding: 25px, Visible Pixels 15px
183 * Edge Padding result: 15px
184 * The user attempts to pan back toward the edge but cannot go past the 15px p adding.
185 * The user then pans 75px away from the edge:
186 * Edge Calculation: System UI: 0px, Image Padding: 15px, Visible Pixels -75px
187 * Edge Padding result: 0px
188 *
189 *
190 * ===== Image Padding and Zooming =====
191 * In the previous section, the ratcheting mechanism was discussed which reduces the padding when
192 * the user pans away from the edge of the screen. However what happens when a user zooms when
193 * padding is applied? If the user is zooming in, then nothing is required as t he image will be
194 * expanded and the padding will be 'absorbed' by the ratcheting effect describe d previously. The
195 * problem occurs when the user is zooming out. In that case, the edge of the i mage is not changed
196 * and the effect looks odd (but is functionally OK).
197 *
198 * The solution to this problem is to reduce the amount of padding by a constant factor. This
199 * reduction creates an easing effect as the position of the image slides toward the edge as the
200 * padding is reduced.
201 *
202 *
203 * ===== Image Padding and Cursors =====
204 * All of the problems and solutions above apply equally to Touch and Trackpad m odes. However
205 * Trackpad mode has two additional problems.
206 *
207 * The first is the problem of newly displayed System UI obscurring the cursor. Imagine you move
208 * the cursor to the upper corner of the screen and then display the toolbar. T he toolbar will be
209 * displayed over the top of the cursor which is not a good idea. Our goal is t o minimize screen
210 * translations, but in this case, it is more important that the user does not l ose sight of the
211 * cursor. Thus we automatically move the viewport so the cursor is guaranteed to be visible. If
212 * the cursor is centered on the screen, then no translation is needed.
213 *
214 * The second is also related to visibility but is not solved by the solution ab ove. For this case,
215 * let's assume the cursor is centered in the viewport. Next the user brings up the Soft Keyboard.
216 * The Keyboard's height is near that of the screen center so the cursor is obsc ured. The user is
217 * not able to see what they are interacting with and selecting a text box is im possible. For this
218 * scenario, we artificially shift the 'screen center' position by viewport_size / 2. This ensures
219 * the cursor is visible and the user can view and interact with any element on the remote desktop.
220 *
14 */ 221 */
15 public class DesktopCanvas { 222 public class DesktopCanvas {
16 /** 223 /**
17 * Maximum allowed zoom level - see {@link #repositionImageWithZoom()}. 224 * Maximum allowed zoom level - see {@link #scaleAndRepositionImage()}.
18 */ 225 */
19 private static final float MAX_ZOOM_FACTOR = 100.0f; 226 private static final float MAX_ZOOM_FACTOR = 100.0f;
20 227
228 /**
229 * Used to smoothly reduce the amount of padding while the user is zooming.
230 */
231 private static final float PADDING_REDUCTION_FACTOR = 0.85f;
232
21 private final RenderStub mRenderStub; 233 private final RenderStub mRenderStub;
22 private final RenderData mRenderData; 234 private final RenderData mRenderData;
23 235
24 /** 236 /**
25 * Represents the actual center of the viewport. This value needs to be a p air of floats so the 237 * 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 238 * of floats so the desktop image can be positioned with sub-pixel accuracy for smoother panning
27 * high zoom levels. 239 * animations at high zoom levels.
28 */ 240 */
29 private PointF mViewportPosition = new PointF(); 241 private PointF mViewportPosition = new PointF();
30 242
31 /** 243 /**
32 * Represents the desired center of the viewport. This value may not repres ent the actual 244 * 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 245 * 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 246 * 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. 247 * positioned with sub-pixel accuracy for smoother panning animations at hig h zoom levels.
36 */ 248 */
37 private PointF mCursorPosition = new PointF(); 249 private PointF mCursorPosition = new PointF();
38 250
39 /** 251 /**
40 * Represents the amount of space, in pixels, used by System UI. 252 * Represents the amount of space, in screen pixels, used by System UI.
41 */ 253 */
42 private Rect mSystemUiOffsetPixels = new Rect(); 254 private Rect mSystemUiOffsetPixels = new Rect();
43 255
256 /**
257 * Represents the additional space, in screen pixels, for each edge of the d esktop image.
258 * Used to allow the user to position the image canvas out from under any vi sible System UI.
259 */
260 private RectF mImagePadding = new RectF();
261
44 public DesktopCanvas(RenderStub renderStub, RenderData renderData) { 262 public DesktopCanvas(RenderStub renderStub, RenderData renderData) {
45 mRenderStub = renderStub; 263 mRenderStub = renderStub;
46 mRenderData = renderData; 264 mRenderData = renderData;
47 } 265 }
48 266
49 /** 267 /**
50 * Sets the desired center position of the viewport (a.k.a. the cursor posit ion) and ensures 268 * 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. 269 * the viewport is updated to include the cursor within it.
52 * 270 *
53 * @param newX The new x coordinate value for the desired center position. 271 * @param newX The new x coordinate value for the desired center position.
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 mRenderData.transform.mapVectors(imageSize); 380 mRenderData.transform.mapVectors(imageSize);
163 381
164 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData .screenHeight) { 382 if (imageSize[0] < mRenderData.screenWidth && imageSize[1] < mRenderData .screenHeight) {
165 // Displayed image is too small in both directions, so apply the min imum zoom 383 // Displayed image is too small in both directions, so apply the min imum zoom
166 // level needed to fit either the width or height. 384 // level needed to fit either the width or height.
167 float scale = Math.min((float) mRenderData.screenWidth / mRenderData .imageWidth, 385 float scale = Math.min((float) mRenderData.screenWidth / mRenderData .imageWidth,
168 (float) mRenderData.screenHeight / mRenderDat a.imageHeight); 386 (float) mRenderData.screenHeight / mRenderDat a.imageHeight);
169 mRenderData.transform.setScale(scale, scale); 387 mRenderData.transform.setScale(scale, scale);
170 } 388 }
171 389
390 // Trim the image padding if the user is zooming out. This prevents cas es where the image
391 // pops to the center when it reaches its minimum size. Note that we do not need to do
392 // anything when the user is zooming in as the canvas will expand and ab sorb the padding.
393 if (scaleFactor < 1.0f) {
394 mImagePadding.set(mImagePadding.left * PADDING_REDUCTION_FACTOR,
395 mImagePadding.top * PADDING_REDUCTION_FACTOR,
396 mImagePadding.right * PADDING_REDUCTION_FACTOR,
397 mImagePadding.bottom * PADDING_REDUCTION_FACTOR);
398 }
399
172 if (centerOnCursor) { 400 if (centerOnCursor) {
173 setCursorPosition(mCursorPosition.x, mCursorPosition.y); 401 setCursorPosition(mCursorPosition.x, mCursorPosition.y);
174 } else { 402 } else {
175 // Find the new screen center (it was probably changed during the zo om operation) and 403 // Find the new screen center (it was probably changed during the zo om operation) and
176 // update the viewport and cursor. 404 // update the viewport and cursor.
177 float[] mappedPoints = { 405 float[] mappedPoints = {
178 ((float) mRenderData.screenWidth / 2), ((float) mRenderData. screenHeight / 2)}; 406 ((float) mRenderData.screenWidth / 2), ((float) mRenderData. screenHeight / 2)};
179 Matrix screenToImage = new Matrix(); 407 Matrix screenToImage = new Matrix();
180 mRenderData.transform.invert(screenToImage); 408 mRenderData.transform.invert(screenToImage);
181 screenToImage.mapPoints(mappedPoints); 409 screenToImage.mapPoints(mappedPoints);
182 // The cursor is mapped to the center of the viewport in this case. 410 // The cursor is mapped to the center of the viewport in this case.
183 setCursorPosition(mappedPoints[0], mappedPoints[1]); 411 setCursorPosition(mappedPoints[0], mappedPoints[1]);
184 } 412 }
185 } 413 }
186 414
187 /** 415 /**
188 * Repositions the image by translating it (without affecting the zoom level ). 416 * Repositions the image by translating it (without affecting the zoom level ).
189 */ 417 */
190 private void repositionImage() { 418 private void repositionImage() {
191 // Map the current viewport position to screen coordinates and adjust th e image position. 419 // Map the current viewport position to screen coordinates and adjust th e image position.
192 float[] viewportPosition = {mViewportPosition.x, mViewportPosition.y}; 420 float[] viewportPosition = {mViewportPosition.x, mViewportPosition.y};
193 mRenderData.transform.mapPoints(viewportPosition); 421 mRenderData.transform.mapPoints(viewportPosition);
194 422
195 float viewportTransX = ((float) mRenderData.screenWidth / 2) - viewportP osition[0]; 423 float viewportTransX = ((float) mRenderData.screenWidth / 2) - viewportP osition[0];
196 float viewportTransY = ((float) mRenderData.screenHeight / 2) - viewport Position[1]; 424 float viewportTransY = ((float) mRenderData.screenHeight / 2) - viewport Position[1];
197 425
198 // Translate the image so the viewport center is displayed in the middle of the screen. 426 // Translate the image so the viewport center is displayed in the middle of the screen.
199 mRenderData.transform.postTranslate(viewportTransX, viewportTransY); 427 mRenderData.transform.postTranslate(viewportTransX, viewportTransY);
200 428
429 adjustImagePadding();
430
201 mRenderStub.setTransformation(mRenderData.transform); 431 mRenderStub.setTransformation(mRenderData.transform);
202 } 432 }
203 433
204 /** 434 /**
205 * Updates the given point such that it refers to a coordinate within the bo unds provided. 435 * Updates the given point such that it refers to a coordinate within the bo unds provided.
206 * 436 *
207 * @param point The point to adjust, the original object is modified. 437 * @param point The point to adjust, the original object is modified.
208 * @param bounds The bounds used to constrain the point. 438 * @param bounds The bounds used to constrain the point.
209 */ 439 */
210 private void constrainPointToBounds(PointF point, RectF bounds) { 440 private void constrainPointToBounds(PointF point, RectF bounds) {
211 if (point.x < bounds.left) { 441 if (point.x < bounds.left) {
212 point.x = bounds.left; 442 point.x = bounds.left;
213 } else if (point.x > bounds.right) { 443 } else if (point.x > bounds.right) {
214 point.x = bounds.right; 444 point.x = bounds.right;
215 } 445 }
216 446
217 if (point.y < bounds.top) { 447 if (point.y < bounds.top) {
218 point.y = bounds.top; 448 point.y = bounds.top;
219 } else if (point.y > bounds.bottom) { 449 } else if (point.y > bounds.bottom) {
220 point.y = bounds.bottom; 450 point.y = bounds.bottom;
221 } 451 }
222 } 452 }
223 453
224 /** Returns a region which defines the set of valid cursor values in image s pace. */ 454 /** Returns a region used to constrain the cursor position in image space. * /
225 private RectF getImageBounds() { 455 private RectF getImageBounds() {
226 return new RectF(0, 0, mRenderData.imageWidth, mRenderData.imageHeight); 456 // Expand the allowable cursor positions to include any applicable paddi ng (includes both
457 // unused System UI padding and currently used image padding). Doing th is allows the user
458 // to move their cursor into this space to indicate they want to scroll it into the viewable
459 // area.
460 RectF systemUiOffsetPixels = getAdjustedSystemUiOffsets();
461 float[] paddingBuffer = {Math.max(mImagePadding.left, systemUiOffsetPixe ls.left),
462 Math.max(mImagePadding.top, systemUiOffsetPixels.top),
463 Math.max(mImagePadding.right, systemUiOffsetPixels.right),
464 Math.max(mImagePadding.bottom, systemUiOffsetPixels.bottom)};
465 Matrix screenToImage = new Matrix();
466 mRenderData.transform.invert(screenToImage);
467 screenToImage.mapVectors(paddingBuffer);
468
469 return new RectF(-paddingBuffer[0], -paddingBuffer[1],
470 mRenderData.imageWidth + paddingBuffer[2],
471 mRenderData.imageHeight + paddingBuffer[3]);
227 } 472 }
228 473
229 /** Returns a region which defines the set of valid viewport center values i n image space. */ 474 /** Returns a region which defines the set of valid viewport center values i n image space. */
230 private RectF getViewportBounds() { 475 private RectF getViewportBounds() {
231 float[] screenVectors = {(float) mRenderData.screenWidth, (float) mRende rData.screenHeight}; 476 float[] screenVectors = {(float) mRenderData.screenWidth, (float) mRende rData.screenHeight};
232 Matrix screenToImage = new Matrix(); 477 Matrix screenToImage = new Matrix();
233 mRenderData.transform.invert(screenToImage); 478 mRenderData.transform.invert(screenToImage);
234 screenToImage.mapVectors(screenVectors); 479 screenToImage.mapVectors(screenVectors);
235 480
236 float xAdjust = 0.0f; 481 PointF letterBoxPadding = getLetterboxPaddingOnScreen();
237 if (mRenderData.imageWidth < screenVectors[0]) { 482 float[] letterBoxPaddingVectors = {letterBoxPadding.x, letterBoxPadding. y};
238 // Image is narrower than the screen, so adjust the bounds to center it. 483 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 484
248 // screenCenter values are 1/2 of a particular screen dimension mapped t o image space. 485 // screenCenter values are 1/2 of a particular screen dimension mapped t o image space.
249 float screenCenterX = screenVectors[0] / 2.0f; 486 float screenCenterX = (screenVectors[0] / 2.0f) - letterBoxPaddingVector s[0];
250 float screenCenterY = screenVectors[1] / 2.0f; 487 float screenCenterY = (screenVectors[1] / 2.0f) - letterBoxPaddingVector s[1];
251 return new RectF(screenCenterX - xAdjust, screenCenterY - yAdjust, 488 RectF imageBounds = getImageBounds();
252 mRenderData.imageWidth - screenCenterX + xAdjust, 489 imageBounds.inset(screenCenterX, screenCenterY);
253 mRenderData.imageHeight - screenCenterY + yAdjust); 490 return imageBounds;
491 }
492
493 /** Returns the letterbox padding needed in each dimension (x and y) in scre en coordinates. */
494 private PointF getLetterboxPaddingOnScreen() {
495 float[] imageVectors = {mRenderData.imageWidth, mRenderData.imageHeight} ;
496 mRenderData.transform.mapVectors(imageVectors);
497
498 // We want to letterbox when the image is smaller than the screen in a s pecific dimension.
499 // Since we center the image, split the difference so it is equally dist ributed.
500 float widthAdjust =
501 Math.max(0.0f, ((float) mRenderData.screenWidth - imageVectors[0 ]) / 2.0f);
502 float heightAdjust =
503 Math.max(0.0f, ((float) mRenderData.screenHeight - imageVectors[ 1]) / 2.0f);
504
505 return new PointF(widthAdjust, heightAdjust);
506 }
507
508 /**
509 * Returns the amount of System UI, adjusted for letterbox padding overlap, to use for padding.
510 */
511 private RectF getAdjustedSystemUiOffsets() {
512 // Ignore negative padding since that means no adjustment is necessary. We use a floor of
513 // 0.0f to simplify calculations using the returned values.
514 PointF letterBoxPadding = getLetterboxPaddingOnScreen();
515 return new RectF(Math.max(mSystemUiOffsetPixels.left - letterBoxPadding. x, 0.0f),
516 Math.max(mSystemUiOffsetPixels.top - letterBoxPadding.y, 0.0f),
517 Math.max(mSystemUiOffsetPixels.right - letterBoxPadding.x, 0.0f) ,
518 Math.max(mSystemUiOffsetPixels.bottom - letterBoxPadding.y, 0.0f ));
519 }
520
521 /**
522 * Updates the padding used to allow the user to scroll the image out from u nder System UI.
523 * This is done by taking the adjusted System UI size, current padding, and visible pixels for
524 * each edge of the screen.
525 */
526 private void adjustImagePadding() {
527 PointF letterBoxPadding = getLetterboxPaddingOnScreen();
528 RectF systemUiOffsetPixels = getAdjustedSystemUiOffsets();
529 float[] imagePoints = {0.0f, 0.0f, mRenderData.imageWidth, mRenderData.i mageHeight};
530 mRenderData.transform.mapPoints(imagePoints);
531
532 mImagePadding.set(
533 adjustEdgePadding(systemUiOffsetPixels.left, mImagePadding.left,
534 imagePoints[0] - letterBoxPadding.x),
535 adjustEdgePadding(systemUiOffsetPixels.top, mImagePadding.top,
536 imagePoints[1] - letterBoxPadding.y),
537 adjustEdgePadding(systemUiOffsetPixels.right, mImagePadding.righ t,
538 mRenderData.screenWidth - imagePoints[2] - letterBoxPadd ing.x),
539 adjustEdgePadding(systemUiOffsetPixels.bottom, mImagePadding.bot tom,
540 mRenderData.screenHeight - imagePoints[3] - letterBoxPad ding.y));
541 }
542
543 /**
544 * Update the current edge padding based on the current System UI and image position state.
545 *
546 * @param systemUiPadding Amount of visible System UI in pixels.
547 * @param currentPadding Amount of padding used, in pixels, for position cal culations.
548 * @param visiblePixels Amount of padding actually visible, in pixels.
549 * @return The new value, in pixels, to be used for positioning.
550 */
551 private float adjustEdgePadding(
552 float systemUiPadding, float currentPadding, float visiblePixels) {
553 float edgeValue;
554 visiblePixels = Math.max(visiblePixels, 0.0f);
555 if (systemUiPadding > 0.0f) {
556 if (systemUiPadding > currentPadding) {
557 // Add enough padding to allow scrolling the desktop out from un der the System UI.
558 edgeValue = Math.min(systemUiPadding, visiblePixels);
559 } else if (systemUiPadding < currentPadding) {
560 // Remove unneeded padding from the canvas.
561 edgeValue = Math.max(systemUiPadding, Math.min(currentPadding, v isiblePixels));
562 } else {
563 // If current and system padding sizes are the same, then keep t he visible portion.
564 edgeValue = Math.min(currentPadding, visiblePixels);
565 }
566 } else if (currentPadding > 0.0f) {
567 // If we have existing padding, then trim if possible, otherwise kee p the same value.
568 edgeValue = Math.min(currentPadding, visiblePixels);
569 } else {
570 // Use zero padding if there is no system or current padding specifi ed.
571 edgeValue = 0.0f;
572 }
573 return edgeValue;
254 } 574 }
255 } 575 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698