/**
   * Implementation of PanZoomTarget Converts a point from layer view coordinates to layer
   * coordinates. In other words, given a point measured in pixels from the top left corner of the
   * layer view, returns the point in pixels measured from the last scroll position we sent to
   * Gecko, in CSS pixels. Assuming the events being sent to Gecko are processed in FIFO order, this
   * calculation should always be correct.
   */
  public PointF convertViewPointToLayerPoint(PointF viewPoint) {
    if (!mGeckoIsReady) {
      return null;
    }

    ImmutableViewportMetrics viewportMetrics = mViewportMetrics;
    PointF origin = viewportMetrics.getOrigin();
    float zoom = viewportMetrics.zoomFactor;
    ImmutableViewportMetrics geckoViewport = mGeckoViewport;
    PointF geckoOrigin = geckoViewport.getOrigin();
    float geckoZoom = geckoViewport.zoomFactor;

    // viewPoint + origin gives the coordinate in device pixels from the top-left corner of the
    // page.
    // Divided by zoom, this gives us the coordinate in CSS pixels from the top-left corner of the
    // page.
    // geckoOrigin / geckoZoom is where Gecko thinks it is (scrollTo position) in CSS pixels from
    // the top-left corner of the page. Subtracting the two gives us the offset of the viewPoint
    // from
    // the current Gecko coordinate in CSS pixels.
    PointF layerPoint =
        new PointF(
            ((viewPoint.x + origin.x) / zoom) - (geckoOrigin.x / geckoZoom),
            ((viewPoint.y + origin.y) / zoom) - (geckoOrigin.y / geckoZoom));

    return layerPoint;
  }
  private void adjustViewport(DisplayPortMetrics displayPort) {
    ImmutableViewportMetrics metrics = getViewportMetrics();
    ImmutableViewportMetrics clampedMetrics = metrics.clamp();

    if (displayPort == null) {
      displayPort =
          DisplayPortCalculator.calculate(metrics, mPanZoomController.getVelocityVector());
    }

    mDisplayPort = displayPort;
    mGeckoViewport = clampedMetrics;

    if (mRecordDrawTimes) {
      mDrawTimingQueue.add(displayPort);
    }

    GeckoAppShell.sendEventToGecko(GeckoEvent.createViewportEvent(clampedMetrics, displayPort));
  }
  /** Sets the current page rect. You must hold the monitor while calling this. */
  private void setPageRect(RectF rect, RectF cssRect) {
    // Since the "rect" is always just a multiple of "cssRect" we don't need to
    // check both; this function assumes that both "rect" and "cssRect" are relative
    // the zoom factor in mViewportMetrics.
    if (mViewportMetrics.getCssPageRect().equals(cssRect)) return;

    mViewportMetrics = mViewportMetrics.setPageRect(rect, cssRect);

    // Page size is owned by the layer client, so no need to notify it of
    // this change.

    post(
        new Runnable() {
          public void run() {
            mPanZoomController.pageRectUpdated();
            mView.requestRender();
          }
        });
  }
  /**
   * The view calls this function to indicate that the viewport changed size. It must hold the
   * monitor while calling it.
   *
   * <p>TODO: Refactor this to use an interface. Expose that interface only to the view and not to
   * the layer client. That way, the layer client won't be tempted to call this, which might result
   * in an infinite loop.
   */
  void setViewportSize(int width, int height) {
    mViewportMetrics = mViewportMetrics.setViewportSize(width, height);

    if (mGeckoIsReady) {
      // here we send gecko a resize message. The code in browser.js is responsible for
      // picking up on that resize event, modifying the viewport as necessary, and informing
      // us of the new viewport.
      sendResizeEventIfNecessary(true);
      // the following call also sends gecko a message, which will be processed after the resize
      // message above has updated the viewport. this message ensures that if we have just put
      // focus in a text field, we scroll the content so that the text field is in view.
      GeckoAppShell.viewSizeChanged();
    }
  }
  /** Viewport message handler. */
  private DisplayPortMetrics handleViewportMessage(
      ImmutableViewportMetrics messageMetrics, ViewportMessageType type) {
    synchronized (this) {
      ImmutableViewportMetrics metrics;
      ImmutableViewportMetrics oldMetrics = getViewportMetrics();

      switch (type) {
        default:
        case UPDATE:
          // Keep the old viewport size
          metrics = messageMetrics.setViewportSize(oldMetrics.getWidth(), oldMetrics.getHeight());
          abortPanZoomAnimation();
          break;
        case PAGE_SIZE:
          // adjust the page dimensions to account for differences in zoom
          // between the rendered content (which is what Gecko tells us)
          // and our zoom level (which may have diverged).
          float scaleFactor = oldMetrics.zoomFactor / messageMetrics.zoomFactor;
          metrics =
              oldMetrics.setPageRect(
                  RectUtils.scale(messageMetrics.getPageRect(), scaleFactor),
                  messageMetrics.getCssPageRect());
          break;
      }

      final ImmutableViewportMetrics newMetrics = metrics;
      post(
          new Runnable() {
            public void run() {
              mGeckoViewport = newMetrics;
            }
          });
      setViewportMetrics(newMetrics, type == ViewportMessageType.UPDATE);
      mDisplayPort = DisplayPortCalculator.calculate(getViewportMetrics(), null);
    }
    return mDisplayPort;
  }
 public FloatSize getViewportSize() {
   return mViewportMetrics.getSize();
 }