| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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.content.Context; | 7 import android.content.Context; |
| 8 import android.graphics.Matrix; | 8 import android.graphics.Matrix; |
| 9 import android.graphics.PointF; | 9 import android.graphics.PointF; |
| 10 import android.graphics.Rect; | 10 import android.graphics.Rect; |
| 11 import android.util.Pair; |
| 11 import android.view.GestureDetector; | 12 import android.view.GestureDetector; |
| 12 import android.view.MotionEvent; | 13 import android.view.MotionEvent; |
| 13 import android.view.ScaleGestureDetector; | 14 import android.view.ScaleGestureDetector; |
| 14 import android.view.ViewConfiguration; | 15 import android.view.ViewConfiguration; |
| 15 | 16 |
| 17 import java.util.ArrayList; |
| 18 import java.util.List; |
| 19 |
| 16 /** | 20 /** |
| 17 * This class is responsible for handling Touch input from the user. Touch even
ts which manipulate | 21 * This class is responsible for handling Touch input from the user. Touch even
ts which manipulate |
| 18 * the local canvas are handled in this class and any input which should be sent
to the remote host | 22 * the local canvas are handled in this class and any input which should be sent
to the remote host |
| 19 * are passed to the InputStrategyInterface implementation set by the DesktopVie
w. | 23 * are passed to the InputStrategyInterface implementation set by the DesktopVie
w. |
| 20 */ | 24 */ |
| 21 public class TouchInputHandler { | 25 public class TouchInputHandler { |
| 22 private static final float EPSILON = 0.001f; | 26 private static final float EPSILON = 0.001f; |
| 23 | 27 |
| 28 private final List<Pair<Object, Event<?>>> mAttachedEvents = new ArrayList<>
(); |
| 24 private final DesktopView mViewer; | 29 private final DesktopView mViewer; |
| 25 private final Context mContext; | 30 private final Context mContext; |
| 26 private final RenderData mRenderData; | 31 private final RenderData mRenderData; |
| 27 private final DesktopCanvas mDesktopCanvas; | 32 private final DesktopCanvas mDesktopCanvas; |
| 28 private InputStrategyInterface mInputStrategy; | 33 private final RenderStub mRenderStub; |
| 29 | 34 private final GestureDetector mScroller; |
| 30 private GestureDetector mScroller; | 35 private final ScaleGestureDetector mZoomer; |
| 31 private ScaleGestureDetector mZoomer; | 36 private final TapGestureDetector mTapDetector; |
| 32 private TapGestureDetector mTapDetector; | |
| 33 | 37 |
| 34 /** Used to disambiguate a 2-finger gesture as a swipe or a pinch. */ | 38 /** Used to disambiguate a 2-finger gesture as a swipe or a pinch. */ |
| 35 private SwipePinchDetector mSwipePinchDetector; | 39 private final SwipePinchDetector mSwipePinchDetector; |
| 36 | 40 |
| 37 // Used for processing cursor & scroller fling animations. | 41 // Used for processing cursor & scroller fling animations. |
| 38 // May consider using a List of AnimationJob if we have more than two animat
ion jobs in | 42 // May consider using a List of AnimationJob if we have more than two animat
ion jobs in |
| 39 // the future. | 43 // the future. |
| 40 private FlingAnimationJob mCursorAnimationJob, mScrollAnimationJob; | 44 private final FlingAnimationJob mCursorAnimationJob; |
| 45 private final FlingAnimationJob mScrollAnimationJob; |
| 46 |
| 47 private InputStrategyInterface mInputStrategy; |
| 41 | 48 |
| 42 /** | 49 /** |
| 43 * Used for tracking swipe gestures. Only the Y-direction is needed for resp
onding to swipe-up | 50 * Used for tracking swipe gestures. Only the Y-direction is needed for resp
onding to swipe-up |
| 44 * or swipe-down. | 51 * or swipe-down. |
| 45 */ | 52 */ |
| 46 private float mTotalMotionY = 0; | 53 private float mTotalMotionY = 0; |
| 47 | 54 |
| 48 /** | 55 /** |
| 49 * Distance in pixels beyond which a motion gesture is considered to be a sw
ipe. This is | 56 * Distance in pixels beyond which a motion gesture is considered to be a sw
ipe. This is |
| 50 * initialized using the Context passed into the ctor. | 57 * initialized using the Context passed into the ctor. |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 public RenderStub.InputFeedbackType getLongPressFeedbackType() { | 180 public RenderStub.InputFeedbackType getLongPressFeedbackType() { |
| 174 return RenderStub.InputFeedbackType.NONE; | 181 return RenderStub.InputFeedbackType.NONE; |
| 175 } | 182 } |
| 176 | 183 |
| 177 @Override | 184 @Override |
| 178 public boolean isIndirectInputMode() { | 185 public boolean isIndirectInputMode() { |
| 179 return false; | 186 return false; |
| 180 } | 187 } |
| 181 } | 188 } |
| 182 | 189 |
| 183 public TouchInputHandler(DesktopView viewer, Context context) { | 190 public TouchInputHandler(DesktopView viewer, Desktop desktop, RenderStub ren
derStub, |
| 191 final InputEventSender injector) { |
| 192 Preconditions.notNull(viewer); |
| 193 Preconditions.notNull(desktop); |
| 194 Preconditions.notNull(renderStub); |
| 195 Preconditions.notNull(injector); |
| 196 |
| 184 mViewer = viewer; | 197 mViewer = viewer; |
| 185 mContext = context; | 198 mContext = desktop; |
| 199 mRenderStub = renderStub; |
| 186 mRenderData = new RenderData(); | 200 mRenderData = new RenderData(); |
| 187 mDesktopCanvas = new DesktopCanvas(mViewer, mRenderData); | 201 mDesktopCanvas = new DesktopCanvas(renderStub, mRenderData); |
| 188 | 202 |
| 189 GestureListener listener = new GestureListener(); | 203 GestureListener listener = new GestureListener(); |
| 190 mScroller = new GestureDetector(context, listener, null, false); | 204 mScroller = new GestureDetector(desktop, listener, null, false); |
| 191 | 205 |
| 192 // If long-press is enabled, the gesture-detector will not emit any furt
her onScroll | 206 // If long-press is enabled, the gesture-detector will not emit any furt
her onScroll |
| 193 // notifications after the onLongPress notification. Since onScroll is b
eing used for | 207 // notifications after the onLongPress notification. Since onScroll is b
eing used for |
| 194 // moving the cursor, it means that the cursor would become stuck if the
finger were held | 208 // moving the cursor, it means that the cursor would become stuck if the
finger were held |
| 195 // down too long. | 209 // down too long. |
| 196 mScroller.setIsLongpressEnabled(false); | 210 mScroller.setIsLongpressEnabled(false); |
| 197 | 211 |
| 198 mZoomer = new ScaleGestureDetector(context, listener); | 212 mZoomer = new ScaleGestureDetector(desktop, listener); |
| 199 mTapDetector = new TapGestureDetector(context, listener); | 213 mTapDetector = new TapGestureDetector(desktop, listener); |
| 200 mSwipePinchDetector = new SwipePinchDetector(context); | 214 mSwipePinchDetector = new SwipePinchDetector(desktop); |
| 201 | 215 |
| 202 // The threshold needs to be bigger than the ScaledTouchSlop used by the
gesture-detectors, | 216 // The threshold needs to be bigger than the ScaledTouchSlop used by the
gesture-detectors, |
| 203 // so that a gesture cannot be both a tap and a swipe. It also needs to
be small enough so | 217 // so that a gesture cannot be both a tap and a swipe. It also needs to
be small enough so |
| 204 // that intentional swipes are usually detected. | 218 // that intentional swipes are usually detected. |
| 205 float density = context.getResources().getDisplayMetrics().density; | 219 float density = desktop.getResources().getDisplayMetrics().density; |
| 206 mSwipeThreshold = 40 * density; | 220 mSwipeThreshold = 40 * density; |
| 207 | 221 |
| 208 mEdgeSlopInPx = ViewConfiguration.get(context).getScaledEdgeSlop(); | 222 mEdgeSlopInPx = ViewConfiguration.get(desktop).getScaledEdgeSlop(); |
| 209 | 223 |
| 210 mInputStrategy = new NullInputStrategy(); | 224 mInputStrategy = new NullInputStrategy(); |
| 211 | 225 |
| 212 mCursorAnimationJob = new CursorAnimationJob(context); | 226 mCursorAnimationJob = new CursorAnimationJob(desktop); |
| 213 mScrollAnimationJob = new ScrollAnimationJob(context); | 227 mScrollAnimationJob = new ScrollAnimationJob(desktop); |
| 214 | 228 |
| 215 mProcessAnimationCallback = new Event.ParameterCallback<Boolean, Void>()
{ | 229 mProcessAnimationCallback = new Event.ParameterCallback<Boolean, Void>()
{ |
| 216 @Override | 230 @Override |
| 217 public Boolean run(Void p) { | 231 public Boolean run(Void p) { |
| 218 return processAnimation(); | 232 return processAnimation(); |
| 219 } | 233 } |
| 220 }; | 234 }; |
| 221 | 235 |
| 222 attachViewEvents(viewer); | 236 attachEvent(mViewer.onTouch(), new Event.ParameterRunnable<TouchEventPar
ameter>() { |
| 237 @Override |
| 238 public void run(TouchEventParameter parameter) { |
| 239 parameter.handled = handleTouchEvent(parameter.event); |
| 240 } |
| 241 }); |
| 242 |
| 243 attachEvent(desktop.onInputModeChanged(), |
| 244 new Event.ParameterRunnable<InputModeChangedEventParameter>() { |
| 245 @Override |
| 246 public void run(InputModeChangedEventParameter parameter) { |
| 247 handleInputModeChanged(parameter, injector); |
| 248 } |
| 249 }); |
| 250 |
| 251 attachEvent(desktop.onSystemUiVisibilityChanged(), |
| 252 new Event.ParameterRunnable<SystemUiVisibilityChangedEventParame
ter>() { |
| 253 @Override |
| 254 public void run(SystemUiVisibilityChangedEventParameter para
meter) { |
| 255 handleSystemUiVisibilityChanged(parameter); |
| 256 } |
| 257 }); |
| 258 |
| 259 attachEvent(renderStub.onClientSizeChanged(), |
| 260 new Event.ParameterRunnable<SizeChangedEventParameter>() { |
| 261 @Override |
| 262 public void run(SizeChangedEventParameter parameter) { |
| 263 handleClientSizeChanged(parameter.width, parameter.heigh
t); |
| 264 } |
| 265 }); |
| 266 |
| 267 attachEvent(renderStub.onHostSizeChanged(), |
| 268 new Event.ParameterRunnable<SizeChangedEventParameter>() { |
| 269 @Override |
| 270 public void run(SizeChangedEventParameter parameter) { |
| 271 handleHostSizeChanged(parameter.width, parameter.height)
; |
| 272 } |
| 273 }); |
| 274 } |
| 275 |
| 276 private <ParamT> void attachEvent(Event<ParamT> event, |
| 277 Event.ParameterRunnable<ParamT> runnable)
{ |
| 278 mAttachedEvents.add(new Pair<Object, Event<?>>(event.add(runnable), even
t)); |
| 223 } | 279 } |
| 224 | 280 |
| 225 /** | 281 /** |
| 282 * Detaches all registered event listeners. This function should be called e
xactly once. |
| 283 */ |
| 284 public void detachEventListeners() { |
| 285 Preconditions.isTrue(!mAttachedEvents.isEmpty()); |
| 286 abortAnimation(); |
| 287 for (Pair<Object, Event<?>> pair : mAttachedEvents) { |
| 288 pair.second.remove(pair.first); |
| 289 } |
| 290 mAttachedEvents.clear(); |
| 291 } |
| 292 |
| 293 /** |
| 226 * Steps forward the animation. | 294 * Steps forward the animation. |
| 227 * @return true if the animation is not finished yet. | 295 * @return true if the animation is not finished yet. |
| 228 */ | 296 */ |
| 229 private boolean processAnimation() { | 297 private boolean processAnimation() { |
| 230 return mCursorAnimationJob.processAnimation() || mScrollAnimationJob.pro
cessAnimation(); | 298 return mCursorAnimationJob.processAnimation() || mScrollAnimationJob.pro
cessAnimation(); |
| 231 } | 299 } |
| 232 | 300 |
| 233 /** | 301 /** |
| 234 * Start stepping animation when onCanvasRendered is triggered. | 302 * Start stepping animation when onCanvasRendered is triggered. |
| 235 */ | 303 */ |
| 236 private void startAnimation() { | 304 private void startAnimation() { |
| 237 mViewer.onCanvasRendered().addSelfRemovable(mProcessAnimationCallback); | 305 mRenderStub.onCanvasRendered().addSelfRemovable(mProcessAnimationCallbac
k); |
| 238 } | 306 } |
| 239 | 307 |
| 240 /** | 308 /** |
| 241 * Abort all animations. | 309 * Abort all animations. |
| 242 */ | 310 */ |
| 243 private void abortAnimation() { | 311 private void abortAnimation() { |
| 244 mCursorAnimationJob.abortAnimation(); | 312 mCursorAnimationJob.abortAnimation(); |
| 245 mScrollAnimationJob.abortAnimation(); | 313 mScrollAnimationJob.abortAnimation(); |
| 246 } | 314 } |
| 247 | 315 |
| 248 public void init(Desktop desktop, final InputEventSender injector) { | |
| 249 Preconditions.notNull(injector); | |
| 250 desktop.onInputModeChanged().add( | |
| 251 new Event.ParameterRunnable<InputModeChangedEventParameter>() { | |
| 252 @Override | |
| 253 public void run(InputModeChangedEventParameter parameter) { | |
| 254 handleInputModeChanged(parameter, injector); | |
| 255 } | |
| 256 }); | |
| 257 | |
| 258 desktop.onSystemUiVisibilityChanged().add( | |
| 259 new Event.ParameterRunnable<SystemUiVisibilityChangedEventParame
ter>() { | |
| 260 @Override | |
| 261 public void run(SystemUiVisibilityChangedEventParameter para
meter) { | |
| 262 handleSystemUiVisibilityChanged(parameter); | |
| 263 } | |
| 264 }); | |
| 265 } | |
| 266 | |
| 267 private void attachViewEvents(DesktopView viewer) { | |
| 268 viewer.onTouch().add(new Event.ParameterRunnable<TouchEventParameter>()
{ | |
| 269 @Override | |
| 270 public void run(TouchEventParameter parameter) { | |
| 271 parameter.handled = handleTouchEvent(parameter.event); | |
| 272 } | |
| 273 }); | |
| 274 viewer.onClientSizeChanged().add(new Event.ParameterRunnable<SizeChanged
EventParameter>() { | |
| 275 @Override | |
| 276 public void run(SizeChangedEventParameter parameter) { | |
| 277 handleClientSizeChanged(parameter.width, parameter.height); | |
| 278 } | |
| 279 }); | |
| 280 viewer.onHostSizeChanged().add(new Event.ParameterRunnable<SizeChangedEv
entParameter>() { | |
| 281 @Override | |
| 282 public void run(SizeChangedEventParameter parameter) { | |
| 283 handleHostSizeChanged(parameter.width, parameter.height); | |
| 284 } | |
| 285 }); | |
| 286 } | |
| 287 | |
| 288 private void handleInputModeChanged( | 316 private void handleInputModeChanged( |
| 289 InputModeChangedEventParameter parameter, InputEventSender injector)
{ | 317 InputModeChangedEventParameter parameter, InputEventSender injector)
{ |
| 290 final Desktop.InputMode inputMode = parameter.inputMode; | 318 final Desktop.InputMode inputMode = parameter.inputMode; |
| 291 final CapabilityManager.HostCapability hostTouchCapability = | 319 final CapabilityManager.HostCapability hostTouchCapability = |
| 292 parameter.hostCapability; | 320 parameter.hostCapability; |
| 293 // We need both input mode and host input capabilities to select the inp
ut | 321 // We need both input mode and host input capabilities to select the inp
ut |
| 294 // strategy. | 322 // strategy. |
| 295 if (!inputMode.isSet() || !hostTouchCapability.isSet()) { | 323 if (!inputMode.isSet() || !hostTouchCapability.isSet()) { |
| 296 return; | 324 return; |
| 297 } | 325 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 309 new SimulatedTouchInputStrategy(mRenderData, injecto
r, mContext)); | 337 new SimulatedTouchInputStrategy(mRenderData, injecto
r, mContext)); |
| 310 } | 338 } |
| 311 break; | 339 break; |
| 312 | 340 |
| 313 default: | 341 default: |
| 314 // Unreachable, but required by Google Java style and findbugs. | 342 // Unreachable, but required by Google Java style and findbugs. |
| 315 assert false : "Unreached"; | 343 assert false : "Unreached"; |
| 316 } | 344 } |
| 317 | 345 |
| 318 // Ensure the cursor state is updated appropriately. | 346 // Ensure the cursor state is updated appropriately. |
| 319 mViewer.cursorVisibilityChanged(mRenderData.drawCursor); | 347 mRenderStub.setCursorVisibility(mRenderData.drawCursor); |
| 320 } | 348 } |
| 321 | 349 |
| 322 private void handleSystemUiVisibilityChanged( | 350 private void handleSystemUiVisibilityChanged( |
| 323 SystemUiVisibilityChangedEventParameter parameter) { | 351 SystemUiVisibilityChangedEventParameter parameter) { |
| 324 if (parameter.softInputMethodVisible) { | 352 if (parameter.softInputMethodVisible) { |
| 325 mDesktopCanvas.setSystemUiOffsetValues(parameter.left, parameter.top
, | 353 mDesktopCanvas.setSystemUiOffsetValues(parameter.left, parameter.top
, |
| 326 mRenderData.screenWidth - parameter.right, | 354 mRenderData.screenWidth - parameter.right, |
| 327 mRenderData.screenHeight - parameter.bottom); | 355 mRenderData.screenHeight - parameter.bottom); |
| 328 } else { | 356 } else { |
| 329 mDesktopCanvas.setSystemUiOffsetValues(0, 0, 0, 0); | 357 mDesktopCanvas.setSystemUiOffsetValues(0, 0, 0, 0); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 moveCursor(imagePoint[0], imagePoint[1]); | 458 moveCursor(imagePoint[0], imagePoint[1]); |
| 431 } | 459 } |
| 432 | 460 |
| 433 /** Moves the cursor to the specified position on the remote host. */ | 461 /** Moves the cursor to the specified position on the remote host. */ |
| 434 private void moveCursor(float newX, float newY) { | 462 private void moveCursor(float newX, float newY) { |
| 435 boolean cursorMoved = mRenderData.setCursorPosition(newX, newY); | 463 boolean cursorMoved = mRenderData.setCursorPosition(newX, newY); |
| 436 if (cursorMoved) { | 464 if (cursorMoved) { |
| 437 mInputStrategy.injectCursorMoveEvent((int) newX, (int) newY); | 465 mInputStrategy.injectCursorMoveEvent((int) newX, (int) newY); |
| 438 } | 466 } |
| 439 | 467 |
| 440 mViewer.cursorMoved(mRenderData.getCursorPosition()); | 468 mRenderStub.moveCursor(mRenderData.getCursorPosition()); |
| 441 } | 469 } |
| 442 | 470 |
| 443 /** Processes a (multi-finger) swipe gesture. */ | 471 /** Processes a (multi-finger) swipe gesture. */ |
| 444 private boolean onSwipe() { | 472 private boolean onSwipe() { |
| 445 if (mTotalMotionY > mSwipeThreshold) { | 473 if (mTotalMotionY > mSwipeThreshold) { |
| 446 // Swipe down occurred. | 474 // Swipe down occurred. |
| 447 mViewer.showActionBar(); | 475 mViewer.showActionBar(); |
| 448 } else if (mTotalMotionY < -mSwipeThreshold) { | 476 } else if (mTotalMotionY < -mSwipeThreshold) { |
| 449 // Swipe up occurred. | 477 // Swipe up occurred. |
| 450 mViewer.showKeyboard(); | 478 mViewer.showKeyboard(); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 609 if (!mInputStrategy.isIndirectInputMode()) { | 637 if (!mInputStrategy.isIndirectInputMode()) { |
| 610 if (screenPointLiesOutsideImageBoundary(x, y)) { | 638 if (screenPointLiesOutsideImageBoundary(x, y)) { |
| 611 return false; | 639 return false; |
| 612 } | 640 } |
| 613 moveCursorToScreenPoint(x, y); | 641 moveCursorToScreenPoint(x, y); |
| 614 } | 642 } |
| 615 | 643 |
| 616 if (mInputStrategy.onTap(button)) { | 644 if (mInputStrategy.onTap(button)) { |
| 617 PointF pos = mRenderData.getCursorPosition(); | 645 PointF pos = mRenderData.getCursorPosition(); |
| 618 | 646 |
| 619 mViewer.showInputFeedback(mInputStrategy.getShortPressFeedbackTy
pe(), pos); | 647 mRenderStub.showInputFeedback(mInputStrategy.getShortPressFeedba
ckType(), pos); |
| 620 } | 648 } |
| 621 return true; | 649 return true; |
| 622 } | 650 } |
| 623 | 651 |
| 624 /** Called when a long-press is triggered for one or more fingers. */ | 652 /** Called when a long-press is triggered for one or more fingers. */ |
| 625 @Override | 653 @Override |
| 626 public void onLongPress(int pointerCount, float x, float y) { | 654 public void onLongPress(int pointerCount, float x, float y) { |
| 627 int button = mouseButtonFromPointerCount(pointerCount); | 655 int button = mouseButtonFromPointerCount(pointerCount); |
| 628 if (button == InputStub.BUTTON_UNDEFINED) { | 656 if (button == InputStub.BUTTON_UNDEFINED) { |
| 629 return; | 657 return; |
| 630 } | 658 } |
| 631 | 659 |
| 632 if (!mInputStrategy.isIndirectInputMode()) { | 660 if (!mInputStrategy.isIndirectInputMode()) { |
| 633 if (screenPointLiesOutsideImageBoundary(x, y)) { | 661 if (screenPointLiesOutsideImageBoundary(x, y)) { |
| 634 return; | 662 return; |
| 635 } | 663 } |
| 636 moveCursorToScreenPoint(x, y); | 664 moveCursorToScreenPoint(x, y); |
| 637 } | 665 } |
| 638 | 666 |
| 639 if (mInputStrategy.onPressAndHold(button)) { | 667 if (mInputStrategy.onPressAndHold(button)) { |
| 640 PointF pos = mRenderData.getCursorPosition(); | 668 PointF pos = mRenderData.getCursorPosition(); |
| 641 | 669 |
| 642 mViewer.showInputFeedback(mInputStrategy.getLongPressFeedbackTyp
e(), pos); | 670 mRenderStub.showInputFeedback(mInputStrategy.getLongPressFeedbac
kType(), pos); |
| 643 mSuppressFling = true; | 671 mSuppressFling = true; |
| 644 mIsDragging = true; | 672 mIsDragging = true; |
| 645 } | 673 } |
| 646 } | 674 } |
| 647 | 675 |
| 648 /** Maps the number of fingers in a tap or long-press gesture to a mouse
-button. */ | 676 /** Maps the number of fingers in a tap or long-press gesture to a mouse
-button. */ |
| 649 private int mouseButtonFromPointerCount(int pointerCount) { | 677 private int mouseButtonFromPointerCount(int pointerCount) { |
| 650 switch (pointerCount) { | 678 switch (pointerCount) { |
| 651 case 1: | 679 case 1: |
| 652 return InputStub.BUTTON_LEFT; | 680 return InputStub.BUTTON_LEFT; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 664 float[] mappedPoints = mapScreenPointToImagePoint(screenX, screenY); | 692 float[] mappedPoints = mapScreenPointToImagePoint(screenX, screenY); |
| 665 | 693 |
| 666 float imageWidth = (float) mRenderData.imageWidth + EPSILON; | 694 float imageWidth = (float) mRenderData.imageWidth + EPSILON; |
| 667 float imageHeight = (float) mRenderData.imageHeight + EPSILON; | 695 float imageHeight = (float) mRenderData.imageHeight + EPSILON; |
| 668 | 696 |
| 669 return mappedPoints[0] < -EPSILON || mappedPoints[0] > imageWidth | 697 return mappedPoints[0] < -EPSILON || mappedPoints[0] > imageWidth |
| 670 || mappedPoints[1] < -EPSILON || mappedPoints[1] > imageHeig
ht; | 698 || mappedPoints[1] < -EPSILON || mappedPoints[1] > imageHeig
ht; |
| 671 } | 699 } |
| 672 } | 700 } |
| 673 } | 701 } |
| OLD | NEW |