private void limitZoom() {
    if (mState.getZoom() > MAX_ZOOM) {
      mState.setZoom(MAX_ZOOM);
    }

    if (mState.getZoom() < MIN_ZOOM) {
      mState.setZoom(MIN_ZOOM);
    }
  }
  public void zoom(float f, float x, float y) {
    final float aspectQuotient = mAspectQuotient.get();

    final float prevZoomX = mState.getZoomX(aspectQuotient);
    final float prevZoomY = mState.getZoomY(aspectQuotient);

    mState.setZoom(mState.getZoom() * f);
    limitZoom();

    final float newZoomX = mState.getZoomX(aspectQuotient);
    final float newZoomY = mState.getZoomY(aspectQuotient);

    mState.setPanX(mState.getPanX() + (x - .5f) * (1f / prevZoomX - 1f / newZoomX));
    mState.setPanY(mState.getPanY() + (y - .5f) * (1f / prevZoomY - 1f / newZoomY));

    limitPan();

    mState.notifyObservers();
  }