docs: boolean restrictStateBounds(State state, State prevState, float pivotX, float pivotY,
              boolean allowOverscroll, boolean allowOverzoom, boolean restrictRotation) {
  
          if (!settings.isRestrictBounds()) {
              return false;
          }
  
          // Calculating default pivot point, if not provided
          if (Float.isNaN(pivotX) || Float.isNaN(pivotY)) {
              GravityUtils.getDefaultPivot(settings, tmpPoint);
              pivotX = tmpPoint.x;
              pivotY = tmpPoint.y;
          }
  
          boolean isStateChanged = false;
  
          if (restrictRotation && settings.isRestrictRotation()) {
              float rotation = Math.round(state.getRotation() / 90f) * 90f;
              if (!State.equals(rotation, state.getRotation())) {
                  state.rotateTo(rotation, pivotX, pivotY);
                  isStateChanged = true;
              }
          }
  
          zoomBounds.set(state);
          final float minZoom = zoomBounds.getMinZoom();
          final float maxZoom = zoomBounds.getMaxZoom();
  
          final float extraZoom = allowOverzoom ? settings.getOverzoomFactor() : 1f;
          float zoom = zoomBounds.restrict(state.getZoom(), extraZoom);
  
          // Applying elastic overzoom
          if (prevState != null) {
              zoom = applyZoomResilience(zoom, prevState.getZoom(), minZoom, maxZoom, extraZoom);
          }
  
          if (!State.equals(zoom, state.getZoom())) {
              state.zoomTo(zoom, pivotX, pivotY);
              isStateChanged = true;
          }
  
          float extraX = allowOverscroll ? settings.getOverscrollDistanceX() : 0f;
          float extraY = allowOverscroll ? settings.getOverscrollDistanceY() : 0f;
  
          movBounds.set(state);
          movBounds.restrict(state.getX(), state.getY(), extraX, extraY, tmpPointF);
          float newX = tmpPointF.x;
          float newY = tmpPointF.y;
  
          if (zoom < minZoom) {
              // Decreasing overscroll if zooming less than minimum zoom
              float factor = (extraZoom * zoom / minZoom - 1f) / (extraZoom - 1f);
              factor = (float) Math.sqrt(factor);
  
              movBounds.restrict(newX, newY, tmpPointF);
              float strictX = tmpPointF.x;
              float strictY = tmpPointF.y;
  
              newX = strictX + factor * (newX - strictX);
              newY = strictY + factor * (newY - strictY);
          }
  
          if (prevState != null) {
              movBounds.getExternalBounds(tmpRectF);
              newX = applyTranslationResilience(newX, prevState.getX(),
                      tmpRectF.left, tmpRectF.right, extraX);
              newY = applyTranslationResilience(newY, prevState.getY(),
                      tmpRectF.top, tmpRectF.bottom, extraY);
          }
  
          if (!State.equals(newX, state.getX()) || !State.equals(newY, state.getY())) {
              state.translateTo(newX, newY);
              isStateChanged = true;
          }
  
          return isStateChanged;
      }