Esempio n. 1
0
  /*
   * A touch point (x,y) occurs in LayerView, this point should be displayed
   * in the center of the zoomed view. The returned point is the position of
   * the Top-Left zoomed view point on the screen device
   */
  private PointF getZoomedViewTopLeftPositionFromTouchPosition(float x, float y) {
    ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
    final float parentWidth = metrics.getWidth();
    final float parentHeight = metrics.getHeight();

    // See comments in getUnzoomedPositionFromPointInZoomedView, but the
    // transformations here are largely the reverse of that function.

    float visibleContentPixels = viewWidth / zoomFactor;
    float maxContentOffset = parentWidth - visibleContentPixels;
    float maxZoomedViewOffset = parentWidth - viewContainerWidth;
    float contentPixelOffset = x - (visibleContentPixels / 2.0f);
    returnValue.x = (int) (contentPixelOffset * (maxZoomedViewOffset / maxContentOffset));

    visibleContentPixels = viewHeight / zoomFactor;
    maxContentOffset = parentHeight - visibleContentPixels;
    maxZoomedViewOffset = parentHeight - (viewContainerHeight - toolbarHeight);
    contentPixelOffset = y - (visibleContentPixels / 2.0f);
    float unscaledViewOffset = layerView.getSurfaceTranslation() - offsetDueToToolBarPosition;
    returnValue.y =
        (int)
            ((contentPixelOffset * (maxZoomedViewOffset / maxContentOffset)) + unscaledViewOffset);

    return returnValue;
  }
  public void handleMessage(String event, JSONObject message) {
    try {
      if (MESSAGE_ZOOM_RECT.equals(event)) {
        float x = (float) message.getDouble("x");
        float y = (float) message.getDouble("y");
        final RectF zoomRect =
            new RectF(x, y, x + (float) message.getDouble("w"), y + (float) message.getDouble("h"));
        mTarget.post(
            new Runnable() {
              public void run() {
                animatedZoomTo(zoomRect);
              }
            });
      } else if (MESSAGE_ZOOM_PAGE.equals(event)) {
        ImmutableViewportMetrics metrics = getMetrics();
        RectF cssPageRect = metrics.getCssPageRect();

        RectF viewableRect = metrics.getCssViewport();
        float y = viewableRect.top;
        // attempt to keep zoom keep focused on the center of the viewport
        float newHeight = viewableRect.height() * cssPageRect.width() / viewableRect.width();
        float dh = viewableRect.height() - newHeight; // increase in the height
        final RectF r = new RectF(0.0f, y + dh / 2, cssPageRect.width(), y + dh / 2 + newHeight);
        mTarget.post(
            new Runnable() {
              public void run() {
                animatedZoomTo(r);
              }
            });
      }
    } catch (Exception e) {
      Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
    }
  }
Esempio n. 3
0
  @Override
  public void requestZoomedViewRender() {
    if (stopUpdateView) {
      return;
    }
    // remove pending runnable
    ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);

    // "requestZoomedViewRender" can be called very often by Gecko (endDrawing in LayerRender)
    // without
    // any thing changed in the zoomed area (useless calls from the "zoomed area" point of view).
    // "requestZoomedViewRender" can take time to re-render the zoomed view, it depends of the
    // complexity
    // of the html on this area.
    // To avoid to slow down the application, the 2 following cases are tested:

    // 1- Last render is still running, plan another render later.
    if (isRendering()) {
      // post a new runnable DELAY_BEFORE_NEXT_RENDER_REQUEST_MS later
      // We need to post with a delay to be sure that the last call to requestZoomedViewRender will
      // be done.
      // For a static html page WITHOUT any animation/video, there is a last call to endDrawing and
      // we need to make
      // the zoomed render on this last call.
      ThreadUtils.postDelayedToUiThread(requestRenderRunnable, DELAY_BEFORE_NEXT_RENDER_REQUEST_MS);
      return;
    }

    // 2- Current render occurs too early, plan another render later.
    if (renderFrequencyTooHigh()) {
      // post a new runnable DELAY_BEFORE_NEXT_RENDER_REQUEST_MS later
      // We need to post with a delay to be sure that the last call to requestZoomedViewRender will
      // be done.
      // For a page WITH animation/video, the animation/video can be stopped, and we need to make
      // the zoomed render on this last call.
      ThreadUtils.postDelayedToUiThread(requestRenderRunnable, DELAY_BEFORE_NEXT_RENDER_REQUEST_MS);
      return;
    }

    startTimeReRender = System.nanoTime();
    // Allocate the buffer if it's the first call.
    // Change the buffer size if it's not the right size.
    updateBufferSize();

    int tabId = Tabs.getInstance().getSelectedTab().getId();

    ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
    PointF origin = metrics.getOrigin();

    final int xPos = (int) origin.x + lastPosition.x;
    final int yPos = (int) origin.y + lastPosition.y;

    GeckoEvent e =
        GeckoEvent.createZoomedViewEvent(
            tabId, xPos, yPos, viewWidth, viewHeight, zoomFactor * metrics.zoomFactor, buffer);
    GeckoAppShell.sendEventToGecko(e);
  }
  private ImmutableViewportMetrics getValidViewportMetrics(
      ImmutableViewportMetrics viewportMetrics) {
    /* First, we adjust the zoom factor so that we can make no overscrolled area visible. */
    float zoomFactor = viewportMetrics.zoomFactor;
    RectF pageRect = viewportMetrics.getPageRect();
    RectF viewport = viewportMetrics.getViewport();

    float focusX = viewport.width() / 2.0f;
    float focusY = viewport.height() / 2.0f;

    float minZoomFactor = 0.0f;
    float maxZoomFactor = MAX_ZOOM;

    ZoomConstraints constraints = mTarget.getZoomConstraints();

    if (constraints.getMinZoom() > 0) minZoomFactor = constraints.getMinZoom();
    if (constraints.getMaxZoom() > 0) maxZoomFactor = constraints.getMaxZoom();

    if (!constraints.getAllowZoom()) {
      // If allowZoom is false, clamp to the default zoom level.
      maxZoomFactor = minZoomFactor = constraints.getDefaultZoom();
    }

    // Ensure minZoomFactor keeps the page at least as big as the viewport.
    if (pageRect.width() > 0) {
      float scaleFactor = viewport.width() / pageRect.width();
      minZoomFactor = Math.max(minZoomFactor, zoomFactor * scaleFactor);
      if (viewport.width() > pageRect.width()) focusX = 0.0f;
    }
    if (pageRect.height() > 0) {
      float scaleFactor = viewport.height() / pageRect.height();
      minZoomFactor = Math.max(minZoomFactor, zoomFactor * scaleFactor);
      if (viewport.height() > pageRect.height()) focusY = 0.0f;
    }

    maxZoomFactor = Math.max(maxZoomFactor, minZoomFactor);

    if (zoomFactor < minZoomFactor) {
      // if one (or both) of the page dimensions is smaller than the viewport,
      // zoom using the top/left as the focus on that axis. this prevents the
      // scenario where, if both dimensions are smaller than the viewport, but
      // by different scale factors, we end up scrolled to the end on one axis
      // after applying the scale
      PointF center = new PointF(focusX, focusY);
      viewportMetrics = viewportMetrics.scaleTo(minZoomFactor, center);
    } else if (zoomFactor > maxZoomFactor) {
      PointF center = new PointF(viewport.width() / 2.0f, viewport.height() / 2.0f);
      viewportMetrics = viewportMetrics.scaleTo(maxZoomFactor, center);
    }

    /* Now we pan to the right origin. */
    viewportMetrics = viewportMetrics.clamp();

    return viewportMetrics;
  }
Esempio n. 5
0
 private void moveUsingGeckoPosition(int leftFromGecko, int topFromGecko) {
   ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
   final float parentHeight = metrics.getHeight();
   // moveToolbar is called before getZoomedViewTopLeftPositionFromTouchPosition in order to
   // correctly center vertically the zoomed area
   moveToolbar((topFromGecko * metrics.zoomFactor > parentHeight / 2));
   PointF convertedPosition =
       getZoomedViewTopLeftPositionFromTouchPosition(
           (leftFromGecko * metrics.zoomFactor), (topFromGecko * metrics.zoomFactor));
   moveZoomedView(
       metrics, convertedPosition.x, convertedPosition.y, StartPointUpdate.GECKO_POSITION);
 }
Esempio n. 6
0
 private void setCapturedSize(ImmutableViewportMetrics metrics) {
   float parentMinSize = Math.min(metrics.getWidth(), metrics.getHeight());
   viewWidth =
       (int) ((parentMinSize * W_CAPTURED_VIEW_IN_PERCENT / (zoomFactor * 100.0)) * zoomFactor);
   viewHeight =
       (int) ((parentMinSize * H_CAPTURED_VIEW_IN_PERCENT / (zoomFactor * 100.0)) * zoomFactor);
   viewContainerHeight = viewHeight + toolbarHeight + 2 * containterSize; // Top and bottom shadows
   viewContainerWidth = viewWidth + 2 * containterSize; // Right and left shadows
   // Display in zoomedview is corrupted when width is an odd number
   // More details about this issue here: bug 776906 comment 11
   viewWidth &= ~0x1;
 }
  /* Performs a bounce-back animation to the given viewport metrics. */
  private void bounce(ImmutableViewportMetrics metrics) {
    stopAnimationTimer();

    ImmutableViewportMetrics bounceStartMetrics = getMetrics();
    if (bounceStartMetrics.fuzzyEquals(metrics)) {
      setState(PanZoomState.NOTHING);
      return;
    }

    // At this point we have already set mState to BOUNCE or ANIMATED_ZOOM, so
    // getRedrawHint() is returning false. This means we can safely call
    // setAnimationTarget to set the new final display port and not have it get
    // clobbered by display ports from intermediate animation frames.
    mTarget.setAnimationTarget(metrics);
    startAnimationTimer(new BounceRunnable(bounceStartMetrics, metrics));
  }
 /* Performs one frame of a bounce animation. */
 private void advanceBounce() {
   synchronized (mTarget.getLock()) {
     float t = easeOut(mBounceFrame * Axis.MS_PER_FRAME / 256f);
     ImmutableViewportMetrics newMetrics = mBounceStartMetrics.interpolate(mBounceEndMetrics, t);
     mTarget.setViewportMetrics(newMetrics);
     mBounceFrame++;
   }
 }
Esempio n. 9
0
  /*
   * Convert a click from ZoomedView. Return the position of the click in the
   * LayerView
   */
  private PointF getUnzoomedPositionFromPointInZoomedView(float x, float y) {
    ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
    final float parentWidth = metrics.getWidth();
    final float parentHeight = metrics.getHeight();
    RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) getLayoutParams();

    // The number of unzoomed content pixels that can be displayed in the
    // zoomed area.
    float visibleContentPixels = viewWidth / zoomFactor;
    // The offset in content pixels of the leftmost zoomed pixel from the
    // layerview's left edge when the zoomed view is moved to the right as
    // far as it can go.
    float maxContentOffset = parentWidth - visibleContentPixels;
    // The maximum offset in screen pixels that the zoomed view can have
    float maxZoomedViewOffset = parentWidth - viewContainerWidth;

    // The above values allow us to compute the term
    //   maxContentOffset / maxZoomedViewOffset
    // which is the number of content pixels that we should move over by
    // for every screen pixel that the zoomed view is moved over by.
    // This allows a smooth transition from when the zoomed view is at the
    // leftmost extent to when it is at the rightmost extent.

    // This is the offset in content pixels of the leftmost zoomed pixel
    // visible in the zoomed view. This value is relative to the layerview
    // edge.
    float zoomedContentOffset =
        ((float) params.leftMargin) * maxContentOffset / maxZoomedViewOffset;
    returnValue.x = (int) (zoomedContentOffset + (x / zoomFactor));

    // Same comments here vertically
    visibleContentPixels = viewHeight / zoomFactor;
    maxContentOffset = parentHeight - visibleContentPixels;
    maxZoomedViewOffset = parentHeight - (viewContainerHeight - toolbarHeight);
    float zoomedAreaOffset =
        (float) params.topMargin + offsetDueToToolBarPosition - layerView.getSurfaceTranslation();
    zoomedContentOffset = zoomedAreaOffset * maxContentOffset / maxZoomedViewOffset;
    returnValue.y = (int) (zoomedContentOffset + ((y - offsetDueToToolBarPosition) / zoomFactor));

    return returnValue;
  }
  /**
   * Zoom to a specified rect IN CSS PIXELS.
   *
   * <p>While we usually use device pixels, @zoomToRect must be specified in CSS pixels.
   */
  private boolean animatedZoomTo(RectF zoomToRect) {
    setState(PanZoomState.ANIMATED_ZOOM);
    final float startZoom = getMetrics().zoomFactor;

    RectF viewport = getMetrics().getViewport();
    // 1. adjust the aspect ratio of zoomToRect to match that of the current viewport,
    // enlarging as necessary (if it gets too big, it will get shrunk in the next step).
    // while enlarging make sure we enlarge equally on both sides to keep the target rect
    // centered.
    float targetRatio = viewport.width() / viewport.height();
    float rectRatio = zoomToRect.width() / zoomToRect.height();
    if (FloatUtils.fuzzyEquals(targetRatio, rectRatio)) {
      // all good, do nothing
    } else if (targetRatio < rectRatio) {
      // need to increase zoomToRect height
      float newHeight = zoomToRect.width() / targetRatio;
      zoomToRect.top -= (newHeight - zoomToRect.height()) / 2;
      zoomToRect.bottom = zoomToRect.top + newHeight;
    } else { // targetRatio > rectRatio) {
      // need to increase zoomToRect width
      float newWidth = targetRatio * zoomToRect.height();
      zoomToRect.left -= (newWidth - zoomToRect.width()) / 2;
      zoomToRect.right = zoomToRect.left + newWidth;
    }

    float finalZoom = viewport.width() / zoomToRect.width();

    ImmutableViewportMetrics finalMetrics = getMetrics();
    finalMetrics =
        finalMetrics.setViewportOrigin(
            zoomToRect.left * finalMetrics.zoomFactor, zoomToRect.top * finalMetrics.zoomFactor);
    finalMetrics = finalMetrics.scaleTo(finalZoom, new PointF(0.0f, 0.0f));

    // 2. now run getValidViewportMetrics on it, so that the target viewport is
    // clamped down to prevent overscroll, over-zoom, and other bad conditions.
    finalMetrics = getValidViewportMetrics(finalMetrics);

    bounce(finalMetrics);
    return true;
  }
 /**
  * Scales the viewport, keeping the given focus point in the same place before and after the scale
  * operation. You must hold the monitor while calling this.
  */
 private void scaleWithFocus(float zoomFactor, PointF focus) {
   ImmutableViewportMetrics viewportMetrics = getMetrics();
   viewportMetrics = viewportMetrics.scaleTo(zoomFactor, focus);
   mTarget.setViewportMetrics(viewportMetrics);
 }