private void computeTabOffsetHelper(RectF stackRect){
  final boolean portrait=mCurrentMode == Orientation.PORTRAIT;
  final float parentWidth=stackRect.width();
  final float parentHeight=stackRect.height();
  final float overscrollPercent=computeOverscrollPercent();
  final float scrollOffset=MathUtils.clamp(mScrollOffset,getMinScroll(false),getMaxScroll(false));
  final float stackScale=getStackScale(stackRect);
  int stackedCount=0;
  float minStackedPosition=0.0f;
  for (int i=0; i < mStackTabs.length; ++i) {
    assert mStackTabs[i] != null;
    StackTab stackTab=mStackTabs[i];
    LayoutTab layoutTab=stackTab.getLayoutTab();
    final float stackScrollOffset=stackTab.isDying() ? mScrollOffsetForDyingTabs : scrollOffset;
    float screenScrollOffset=approxScreen(stackTab,stackScrollOffset);
    screenScrollOffset=Math.max(minStackedPosition,screenScrollOffset);
    if (stackedCount < MAX_NUMBER_OF_STACKED_TABS_TOP) {
      final float tiltXcos=(float)Math.cos(Math.toRadians(layoutTab.getTiltX()));
      final float tiltYcos=(float)Math.cos(Math.toRadians(layoutTab.getTiltY()));
      float collapse=Math.min(Math.abs(tiltXcos),Math.abs(tiltYcos));
      collapse*=layoutTab.getAlpha();
      minStackedPosition+=StackTab.sStackedTabVisibleSize * collapse;
    }
    stackedCount+=stackTab.isDying() ? 0 : 1;
    if (overscrollPercent < 0) {
      screenScrollOffset+=(overscrollPercent / OVERSCROLL_TOP_SLIDE_PCTG) * screenScrollOffset;
      screenScrollOffset=Math.max(0,screenScrollOffset);
    }
    float xIn=(parentWidth - layoutTab.getScaledContentWidth()) / 2.0f;
    float yIn=(parentHeight - layoutTab.getScaledContentHeight()) / 2.0f;
    final float horizontalPadding=(parentWidth - layoutTab.getOriginalContentWidth() * StackAnimation.SCALE_AMOUNT * stackScale) / 2.0f;
    final float verticalPadding=(parentHeight - layoutTab.getOriginalContentHeight() * StackAnimation.SCALE_AMOUNT * stackScale) / 2.0f;
    if (portrait) {
      yIn+=STACK_PORTRAIT_Y_OFFSET_PROPORTION * verticalPadding;
      yIn+=screenScrollOffset;
    }
 else {
      if (LocalizationUtils.isLayoutRtl()) {
        xIn-=STACK_LANDSCAPE_START_OFFSET_PROPORTION * horizontalPadding;
        xIn-=screenScrollOffset;
      }
 else {
        xIn+=STACK_LANDSCAPE_START_OFFSET_PROPORTION * horizontalPadding;
        xIn+=screenScrollOffset;
      }
      yIn+=STACK_LANDSCAPE_Y_OFFSET_PROPORTION * verticalPadding;
    }
    layoutTab.setX(xIn);
    layoutTab.setY(yIn);
  }
  stackedCount=0;
  float maxStackedPosition=portrait ? mLayout.getHeightMinusTopControls() : mLayout.getWidth();
  for (int i=mStackTabs.length - 1; i >= 0; i--) {
    assert mStackTabs[i] != null;
    StackTab stackTab=mStackTabs[i];
    LayoutTab layoutTab=stackTab.getLayoutTab();
    if (stackTab.isDying())     continue;
    float pos;
    if (portrait) {
      pos=layoutTab.getY();
      layoutTab.setY(Math.min(pos,maxStackedPosition));
    }
 else     if (LocalizationUtils.isLayoutRtl()) {
      float posOffset=mLayout.getWidth() - layoutTab.getOriginalContentWidth() * StackAnimation.SCALE_AMOUNT * stackScale;
      pos=-layoutTab.getX() + posOffset;
      layoutTab.setX(-Math.min(pos,maxStackedPosition) + posOffset);
    }
 else {
      pos=layoutTab.getX();
      layoutTab.setX(Math.min(pos,maxStackedPosition));
    }
    if (pos >= maxStackedPosition && stackedCount < MAX_NUMBER_OF_STACKED_TABS_BOTTOM) {
      maxStackedPosition-=StackTab.sStackedTabVisibleSize;
      stackedCount++;
    }
  }
  final float discardRange=getDiscardRange();
  for (int i=0; i < mStackTabs.length; ++i) {
    assert mStackTabs[i] != null;
    StackTab stackTab=mStackTabs[i];
    LayoutTab layoutTab=stackTab.getLayoutTab();
    final float xIn=layoutTab.getX() + stackTab.getXInStackOffset();
    final float yIn=layoutTab.getY() + stackTab.getYInStackOffset();
    final float xOut=stackTab.getXOutOfStack();
    final float yOut=stackTab.getYOutOfStack();
    float x=MathUtils.interpolate(xOut,xIn,stackTab.getXInStackInfluence());
    float y=MathUtils.interpolate(yOut,yIn,stackTab.getYInStackInfluence());
    if (stackTab.getDiscardAmount() != 0) {
      float discard=stackTab.getDiscardAmount();
      boolean fromClick=stackTab.getDiscardFromClick();
      float scale=computeDiscardScale(discard,discardRange,fromClick);
      float deltaX=stackTab.getDiscardOriginX() - stackTab.getLayoutTab().getOriginalContentWidth() / 2.f;
      float deltaY=stackTab.getDiscardOriginY() - stackTab.getLayoutTab().getOriginalContentHeight() / 2.f;
      float discardOffset=fromClick ? 0.f : discard;
      if (portrait) {
        x+=discardOffset + deltaX * (1.f - scale);
        y+=deltaY * (1.f - scale);
      }
 else {
        x+=deltaX * (1.f - scale);
        y+=discardOffset + deltaY * (1.f - scale);
      }
    }
    layoutTab.setX(stackRect.left + x);
    layoutTab.setY(stackRect.top + y);
  }
}

private void computeTabOffsetHelper ( RectF stackRect ) { final boolean portrait = mCurrentMode == Orientation . PORTRAIT ; final float parentWidth = stackRect . width ( ) ; final float parentHeight = stackRect . height ( ) ; final float overscrollPercent = computeOverscrollPercent ( ) ; final float scrollOffset = MathUtils . clamp ( mScrollOffset , getMinScroll ( false ) , getMaxScroll ( false ) ) ; final float stackScale = getStackScale ( stackRect ) ; int stackedCount = 0 ; float minStackedPosition = 0.0f ; for ( int i = 0 ; i < mStackTabs . length ; ++ i ) { assert mStackTabs [ i ] != null ; StackTab stackTab = mStackTabs [ i ] ; LayoutTab layoutTab = stackTab . getLayoutTab ( ) ; final float stackScrollOffset = stackTab . isDying ( ) ? mScrollOffsetForDyingTabs : scrollOffset ; float screenScrollOffset = approxScreen ( stackTab , stackScrollOffset ) ; screenScrollOffset = Math . max ( minStackedPosition , screenScrollOffset ) ; if ( stackedCount < MAX_NUMBER_OF_STACKED_TABS_TOP ) { final float tiltXcos = ( float ) Math . cos ( Math . toRadians ( layoutTab . getTiltX ( ) ) ) ; final float tiltYcos = ( float ) Math . cos ( Math . toRadians ( layoutTab . getTiltY ( ) ) ) ; float collapse = Math . min ( Math . abs ( tiltXcos ) , Math . abs ( tiltYcos ) ) ; collapse *= layoutTab . getAlpha ( ) ; minStackedPosition += StackTab . sStackedTabVisibleSize * collapse ; } stackedCount += stackTab . isDying ( ) ? 0 : 1 ; if ( overscrollPercent < 0 ) { screenScrollOffset += ( overscrollPercent / OVERSCROLL_TOP_SLIDE_PCTG ) * screenScrollOffset ; screenScrollOffset = Math . max ( 0 , screenScrollOffset ) ; } float xIn = ( parentWidth - layoutTab . getScaledContentWidth ( ) ) / 2.0f ; float yIn = ( parentHeight - layoutTab . getScaledContentHeight ( ) ) / 2.0f ; final float horizontalPadding = ( parentWidth - layoutTab . getOriginalContentWidth ( ) * StackAnimation . SCALE_AMOUNT * stackScale ) / 2.0f ; final float verticalPadding = ( parentHeight - layoutTab . getOriginalContentHeight ( ) * StackAnimation . SCALE_AMOUNT * stackScale ) / 2.0f ; if ( portrait ) { yIn += STACK_PORTRAIT_Y_OFFSET_PROPORTION * verticalPadding ; yIn += screenScrollOffset ; } else { if ( LocalizationUtils . isLayoutRtl ( ) ) { xIn -= STACK_LANDSCAPE_START_OFFSET_PROPORTION * horizontalPadding ; xIn -= screenScrollOffset ; } else { xIn += STACK_LANDSCAPE_START_OFFSET_PROPORTION * horizontalPadding ; xIn += screenScrollOffset ; } yIn += STACK_LANDSCAPE_Y_OFFSET_PROPORTION * verticalPadding ; } layoutTab . setX ( xIn ) ; layoutTab . setY ( yIn ) ; } stackedCount = 0 ; float maxStackedPosition = portrait ? mLayout . getHeightMinusTopControls ( ) : mLayout . getWidth ( ) ; for ( int i = mStackTabs . length - 1 ; i >= 0 ; i -- ) { assert mStackTabs [ i ] != null ; StackTab stackTab = mStackTabs [ i ] ; LayoutTab layoutTab = stackTab . getLayoutTab ( ) ; if ( stackTab . isDying ( ) ) continue ; float pos ; if ( portrait ) { pos = layoutTab . getY ( ) ; layoutTab . setY ( Math . min ( pos , maxStackedPosition ) ) ; } else if ( LocalizationUtils . isLayoutRtl ( ) ) { float posOffset = mLayout . getWidth ( ) - layoutTab . getOriginalContentWidth ( ) * StackAnimation . SCALE_AMOUNT * stackScale ; pos = - layoutTab . getX ( ) + posOffset ; layoutTab . setX ( - Math . min ( pos , maxStackedPosition ) + posOffset ) ; } else { pos = layoutTab . getX ( ) ; layoutTab . setX ( Math . min ( pos , maxStackedPosition ) ) ; } if ( pos >= maxStackedPosition && stackedCount < MAX_NUMBER_OF_STACKED_TABS_BOTTOM ) { maxStackedPosition -= StackTab . sStackedTabVisibleSize ; stackedCount ++ ; } } final float discardRange = getDiscardRange ( ) ; for ( int i = 0 ; i < mStackTabs . length ; ++ i ) { assert mStackTabs [ i ] != null ; StackTab stackTab = mStackTabs [ i ] ; LayoutTab layoutTab = stackTab . getLayoutTab ( ) ; final float xIn = layoutTab . getX ( ) + stackTab . getXInStackOffset ( ) ; final float yIn = layoutTab . getY ( ) + stackTab . getYInStackOffset ( ) ; final float xOut = stackTab . getXOutOfStack ( ) ; final float yOut = stackTab . getYOutOfStack ( ) ; float x = MathUtils . interpolate ( xOut , xIn , stackTab . getXInStackInfluence ( ) ) ; float y = MathUtils . interpolate ( yOut , yIn , stackTab . getYInStackInfluence ( ) ) ; if ( stackTab . getDiscardAmount ( ) != 0 ) { float discard = stackTab . getDiscardAmount ( ) ; boolean fromClick = stackTab . getDiscardFromClick ( ) ; float scale = computeDiscardScale ( discard , discardRange , fromClick ) ; float deltaX = stackTab . getDiscardOriginX ( ) - stackTab . getLayoutTab ( ) . getOriginalContentWidth ( ) / 2.f ; float deltaY = stackTab . getDiscardOriginY ( ) - stackTab . getLayoutTab ( ) . getOriginalContentHeight ( ) / 2.f ; float discardOffset = fromClick ? 0.f : discard ; if ( portrait ) { x += discardOffset + deltaX * ( 1.f - scale ) ; y += deltaY * ( 1.f - scale ) ; } else { x += deltaX * ( 1.f - scale ) ; y += discardOffset + deltaY * ( 1.f - scale ) ; } } layoutTab . setX ( stackRect . left + x ) ; layoutTab . setY ( stackRect . top + y ) ; } }
computetabposition pass 3 : compute the position of the tabs . adjust for top and bottom stacking .
