-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
* canvas and touch events to display the on-demand zoom magnifier.
*/
class PopupZoomer extends View {
- private static String LOGTAG = "PopupZoomer";
+ private static final String LOGTAG = "PopupZoomer";
// The padding between the edges of the view and the popup. Note that there is a mirror
// constant in content/renderer/render_view_impl.cc which should be kept in sync if
private GestureDetector mGestureDetector;
+ // These bounds are computed and valid for one execution of onDraw.
+ // Extracted to a member variable to save unnecessary allocations on each invocation.
+ private RectF mDrawRect;
+
private static float getOverlayCornerRadius(Context context) {
if (sOverlayCornerRadius == 0) {
try {
setFocusableInTouchMode(true);
GestureDetector.SimpleOnGestureListener listener =
- new GestureDetector.SimpleOnGestureListener() {
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- if (mAnimating) return true;
-
- if (isTouchOutsideArea(e1.getX(), e1.getY())) {
- hide(true);
- } else {
- scroll(distanceX, distanceY);
- }
- return true;
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- return handleTapOrPress(e, false);
- }
-
- @Override
- public void onLongPress(MotionEvent e) {
- handleTapOrPress(e, true);
- }
-
- private boolean handleTapOrPress(MotionEvent e, boolean isLongPress) {
- if (mAnimating) return true;
-
- float x = e.getX();
- float y = e.getY();
- if (isTouchOutsideArea(x, y)) {
- // User clicked on area outside the popup.
- hide(true);
- } else if (mOnTapListener != null) {
- PointF converted = convertTouchPoint(x, y);
- MotionEvent event = MotionEvent.obtainNoHistory(e);
- event.setLocation(converted.x, converted.y);
- if (isLongPress) {
- mOnTapListener.onLongPress(PopupZoomer.this, event);
+ new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2,
+ float distanceX, float distanceY) {
+ if (mAnimating) return true;
+
+ if (isTouchOutsideArea(e1.getX(), e1.getY())) {
+ hide(true);
} else {
- mOnTapListener.onSingleTap(PopupZoomer.this, event);
+ scroll(distanceX, distanceY);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onSingleTapUp(MotionEvent e) {
+ return handleTapOrPress(e, false);
+ }
+
+ @Override
+ public void onLongPress(MotionEvent e) {
+ handleTapOrPress(e, true);
+ }
+
+ private boolean handleTapOrPress(MotionEvent e, boolean isLongPress) {
+ if (mAnimating) return true;
+
+ float x = e.getX();
+ float y = e.getY();
+ if (isTouchOutsideArea(x, y)) {
+ // User clicked on area outside the popup.
+ hide(true);
+ } else if (mOnTapListener != null) {
+ PointF converted = convertTouchPoint(x, y);
+ MotionEvent event = MotionEvent.obtainNoHistory(e);
+ event.setLocation(converted.x, converted.y);
+ if (isLongPress) {
+ mOnTapListener.onLongPress(PopupZoomer.this, event);
+ } else {
+ mOnTapListener.onSingleTap(PopupZoomer.this, event);
+ }
+ hide(true);
}
- hide(true);
+ return true;
}
- return true;
- }
- };
+ };
mGestureDetector = new GestureDetector(context, listener);
}
// Constrain initial scroll position within allowed bounds.
mPopupScrollX = constrain(mPopupScrollX, mMinScrollX, mMaxScrollX);
mPopupScrollY = constrain(mPopupScrollY, mMinScrollY, mMaxScrollY);
+
+ // Compute the bounds in onDraw()
+ mDrawRect = new RectF();
}
/*
// Since we want the content to appear directly above its counterpart on the
// page, we need to remove the mShiftX/Y effect at the beginning of the animation.
// The unshifting decreases with the animation.
- float unshiftX = - mShiftX * (1.0f - fractionAnimation) / mScale;
- float unshiftY = - mShiftY * (1.0f - fractionAnimation) / mScale;
+ float unshiftX = -mShiftX * (1.0f - fractionAnimation) / mScale;
+ float unshiftY = -mShiftY * (1.0f - fractionAnimation) / mScale;
- // Compute the rect to show.
- RectF rect = new RectF();
- rect.left = mTouch.x - mLeftExtrusion * scale + unshiftX;
- rect.top = mTouch.y - mTopExtrusion * scale + unshiftY;
- rect.right = mTouch.x + mRightExtrusion * scale + unshiftX;
- rect.bottom = mTouch.y + mBottomExtrusion * scale + unshiftY;
- canvas.clipRect(rect);
+ // Compute the |mDrawRect| to show.
+ mDrawRect.left = mTouch.x - mLeftExtrusion * scale + unshiftX;
+ mDrawRect.top = mTouch.y - mTopExtrusion * scale + unshiftY;
+ mDrawRect.right = mTouch.x + mRightExtrusion * scale + unshiftX;
+ mDrawRect.bottom = mTouch.y + mBottomExtrusion * scale + unshiftY;
+ canvas.clipRect(mDrawRect);
// Since the canvas transform APIs all pre-concat the transformations, this is done in
// reverse order. The canvas is first scaled up, then shifted the appropriate amount of
// pixels.
- canvas.scale(scale, scale, rect.left, rect.top);
+ canvas.scale(scale, scale, mDrawRect.left, mDrawRect.top);
canvas.translate(mPopupScrollX, mPopupScrollY);
- canvas.drawBitmap(mZoomedBitmap, rect.left, rect.top, null);
+ canvas.drawBitmap(mZoomedBitmap, mDrawRect.left, mDrawRect.top, null);
canvas.restore();
Drawable overlayNineTile = getOverlayDrawable(getContext());
- overlayNineTile.setBounds((int) rect.left - sOverlayPadding.left,
- (int) rect.top - sOverlayPadding.top,
- (int) rect.right + sOverlayPadding.right,
- (int) rect.bottom + sOverlayPadding.bottom);
+ overlayNineTile.setBounds((int) mDrawRect.left - sOverlayPadding.left,
+ (int) mDrawRect.top - sOverlayPadding.top,
+ (int) mDrawRect.right + sOverlayPadding.right,
+ (int) mDrawRect.bottom + sOverlayPadding.bottom);
// TODO(nileshagrawal): We should use time here instead of fractionAnimation
// as fractionAnimaton is interpolated and can go over 1.
int alpha = constrain((int) (fractionAnimation * 255), 0, 255);
/**
* Show the PopupZoomer view with given target bounds.
*/
- public void show(Rect rect){
+ public void show(Rect rect) {
if (mShowing || mZoomedBitmap == null) return;
setTargetBounds(rect);
* Hide the PopupZoomer view.
* @param animation true if hide with animation.
*/
- public void hide(boolean animation){
+ public void hide(boolean animation) {
if (!mShowing) return;
if (animation) {