LCOV - code coverage report
Current view: directory - layout/generic - nsGfxScrollFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1659 0 0.0 %
Date: 2012-06-02 Functions: 156 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      24                 :  *   Mats Palmgren <matspal@gmail.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : /* rendering object to wrap rendering objects that should be scrollable */
      41                 : 
      42                 : #include "nsCOMPtr.h"
      43                 : #include "nsHTMLParts.h"
      44                 : #include "nsPresContext.h"
      45                 : #include "nsIServiceManager.h"
      46                 : #include "nsIView.h"
      47                 : #include "nsIScrollable.h"
      48                 : #include "nsIViewManager.h"
      49                 : #include "nsContainerFrame.h"
      50                 : #include "nsGfxScrollFrame.h"
      51                 : #include "nsGkAtoms.h"
      52                 : #include "nsINameSpaceManager.h"
      53                 : #include "nsIDocument.h"
      54                 : #include "nsFontMetrics.h"
      55                 : #include "nsIDocumentObserver.h"
      56                 : #include "nsBoxLayoutState.h"
      57                 : #include "nsINodeInfo.h"
      58                 : #include "nsScrollbarFrame.h"
      59                 : #include "nsIScrollbarMediator.h"
      60                 : #include "nsITextControlFrame.h"
      61                 : #include "nsIDOMHTMLTextAreaElement.h"
      62                 : #include "nsNodeInfoManager.h"
      63                 : #include "nsIURI.h"
      64                 : #include "nsGUIEvent.h"
      65                 : #include "nsContentCreatorFunctions.h"
      66                 : #include "nsISupportsPrimitives.h"
      67                 : #include "nsAutoPtr.h"
      68                 : #include "nsPresState.h"
      69                 : #include "nsDocShellCID.h"
      70                 : #include "nsIHTMLDocument.h"
      71                 : #include "nsEventDispatcher.h"
      72                 : #include "nsContentUtils.h"
      73                 : #include "nsLayoutUtils.h"
      74                 : #ifdef ACCESSIBILITY
      75                 : #include "nsAccessibilityService.h"
      76                 : #endif
      77                 : #include "nsBidiUtils.h"
      78                 : #include "nsFrameManager.h"
      79                 : #include "mozilla/Preferences.h"
      80                 : #include "mozilla/LookAndFeel.h"
      81                 : #include "mozilla/dom/Element.h"
      82                 : #include "FrameLayerBuilder.h"
      83                 : #include "nsSMILKeySpline.h"
      84                 : #include "nsSubDocumentFrame.h"
      85                 : 
      86                 : using namespace mozilla;
      87                 : using namespace mozilla::dom;
      88                 : 
      89                 : //----------------------------------------------------------------------
      90                 : 
      91                 : //----------nsHTMLScrollFrame-------------------------------------------
      92                 : 
      93                 : nsIFrame*
      94               0 : NS_NewHTMLScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot)
      95                 : {
      96               0 :   return new (aPresShell) nsHTMLScrollFrame(aPresShell, aContext, aIsRoot);
      97                 : }
      98                 : 
      99               0 : NS_IMPL_FRAMEARENA_HELPERS(nsHTMLScrollFrame)
     100                 : 
     101               0 : nsHTMLScrollFrame::nsHTMLScrollFrame(nsIPresShell* aShell, nsStyleContext* aContext, bool aIsRoot)
     102                 :   : nsContainerFrame(aContext),
     103               0 :     mInner(this, aIsRoot)
     104                 : {
     105               0 : }
     106                 : 
     107                 : nsresult
     108               0 : nsHTMLScrollFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
     109                 : {
     110               0 :   return mInner.CreateAnonymousContent(aElements);
     111                 : }
     112                 : 
     113                 : void
     114               0 : nsHTMLScrollFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
     115                 :                                             PRUint32 aFilter)
     116                 : {
     117               0 :   mInner.AppendAnonymousContentTo(aElements, aFilter);
     118               0 : }
     119                 : 
     120                 : void
     121               0 : nsHTMLScrollFrame::DestroyFrom(nsIFrame* aDestructRoot)
     122                 : {
     123               0 :   mInner.Destroy();
     124               0 :   DestroyAbsoluteFrames(aDestructRoot);
     125               0 :   nsContainerFrame::DestroyFrom(aDestructRoot);
     126               0 : }
     127                 : 
     128                 : NS_IMETHODIMP
     129               0 : nsHTMLScrollFrame::SetInitialChildList(ChildListID  aListID,
     130                 :                                        nsFrameList& aChildList)
     131                 : {
     132               0 :   nsresult rv = nsContainerFrame::SetInitialChildList(aListID, aChildList);
     133               0 :   mInner.ReloadChildFrames();
     134               0 :   return rv;
     135                 : }
     136                 : 
     137                 : 
     138                 : NS_IMETHODIMP
     139               0 : nsHTMLScrollFrame::AppendFrames(ChildListID  aListID,
     140                 :                                 nsFrameList& aFrameList)
     141                 : {
     142               0 :   NS_ASSERTION(aListID == kPrincipalList, "Only main list supported");
     143               0 :   mFrames.AppendFrames(nsnull, aFrameList);
     144               0 :   mInner.ReloadChildFrames();
     145               0 :   return NS_OK;
     146                 : }
     147                 : 
     148                 : NS_IMETHODIMP
     149               0 : nsHTMLScrollFrame::InsertFrames(ChildListID aListID,
     150                 :                                 nsIFrame* aPrevFrame,
     151                 :                                 nsFrameList& aFrameList)
     152                 : {
     153               0 :   NS_ASSERTION(aListID == kPrincipalList, "Only main list supported");
     154               0 :   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
     155                 :                "inserting after sibling frame with different parent");
     156               0 :   mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
     157               0 :   mInner.ReloadChildFrames();
     158               0 :   return NS_OK;
     159                 : }
     160                 : 
     161                 : NS_IMETHODIMP
     162               0 : nsHTMLScrollFrame::RemoveFrame(ChildListID aListID,
     163                 :                                nsIFrame* aOldFrame)
     164                 : {
     165               0 :   NS_ASSERTION(aListID == kPrincipalList, "Only main list supported");
     166               0 :   mFrames.DestroyFrame(aOldFrame);
     167               0 :   mInner.ReloadChildFrames();
     168               0 :   return NS_OK;
     169                 : }
     170                 : 
     171                 : nsSplittableType
     172               0 : nsHTMLScrollFrame::GetSplittableType() const
     173                 : {
     174               0 :   return NS_FRAME_NOT_SPLITTABLE;
     175                 : }
     176                 : 
     177                 : PRIntn
     178               0 : nsHTMLScrollFrame::GetSkipSides() const
     179                 : {
     180               0 :   return 0;
     181                 : }
     182                 : 
     183                 : nsIAtom*
     184               0 : nsHTMLScrollFrame::GetType() const
     185                 : {
     186               0 :   return nsGkAtoms::scrollFrame; 
     187                 : }
     188                 : 
     189                 : void
     190               0 : nsHTMLScrollFrame::InvalidateInternal(const nsRect& aDamageRect,
     191                 :                                       nscoord aX, nscoord aY, nsIFrame* aForChild,
     192                 :                                       PRUint32 aFlags)
     193                 : {
     194               0 :   if (aForChild) {
     195               0 :     if (aForChild == mInner.mScrolledFrame) {
     196               0 :       nsRect damage = aDamageRect + nsPoint(aX, aY);
     197                 :       // This is the damage rect that we're going to pass up to our parent.
     198               0 :       nsRect parentDamage;
     199               0 :       if (mInner.IsIgnoringViewportClipping()) {
     200               0 :         parentDamage = damage;
     201                 :       } else {
     202                 :         // If we're using a displayport, we might be displaying an area
     203                 :         // different than our scroll port and the damage needs to be
     204                 :         // clipped to that instead.
     205               0 :         nsRect displayport;
     206                 :         bool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(),
     207               0 :                                                                 &displayport);
     208               0 :         if (usingDisplayport) {
     209               0 :           parentDamage.IntersectRect(damage, displayport);
     210                 :         } else {
     211               0 :           parentDamage.IntersectRect(damage, mInner.mScrollPort);
     212                 :         }
     213                 :       }
     214                 : 
     215               0 :       if (IsScrollingActive()) {
     216                 :         // This is the damage rect that we're going to pass up and
     217                 :         // only request invalidation of ThebesLayers for.
     218                 :         // damage is now in our coordinate system, which means it was
     219                 :         // translated using the current scroll position. Adjust it to
     220                 :         // reflect the scroll position at last paint, since that's what
     221                 :         // the ThebesLayers are currently set up for.
     222                 :         // This should not be clipped to the scrollport since ThebesLayers
     223                 :         // can contain content outside the scrollport that may need to be
     224                 :         // invalidated.
     225               0 :         nsRect thebesLayerDamage = damage + GetScrollPosition() - mInner.mScrollPosAtLastPaint;
     226               0 :         if (parentDamage.IsEqualInterior(thebesLayerDamage)) {
     227                 :           // This single call will take care of both rects
     228               0 :           nsContainerFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags);
     229                 :         } else {
     230                 :           // Invalidate rects separately
     231               0 :           if (!(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
     232                 :             nsContainerFrame::InvalidateInternal(thebesLayerDamage, 0, 0, aForChild,
     233               0 :                                                  aFlags | INVALIDATE_ONLY_THEBES_LAYERS);
     234                 :           }
     235               0 :           if (!(aFlags & INVALIDATE_ONLY_THEBES_LAYERS) && !parentDamage.IsEmpty()) {
     236                 :             nsContainerFrame::InvalidateInternal(parentDamage, 0, 0, aForChild,
     237               0 :                                                  aFlags | INVALIDATE_NO_THEBES_LAYERS);
     238                 :           }
     239                 :         }
     240                 :       } else {
     241               0 :         if (!parentDamage.IsEmpty()) {
     242               0 :           nsContainerFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags);
     243                 :         }
     244                 :       }
     245                 : 
     246               0 :       if (mInner.mIsRoot && !parentDamage.IsEqualInterior(damage)) {
     247                 :         // Make sure we notify our prescontext about invalidations outside
     248                 :         // viewport clipping.
     249                 :         // This is important for things that are snapshotting the viewport,
     250                 :         // possibly outside the scrolled bounds.
     251                 :         // We don't need to propagate this any further up, though. Anyone who
     252                 :         // cares about scrolled-out-of-view invalidates had better be listening
     253                 :         // to our window directly.
     254               0 :         PresContext()->NotifyInvalidation(damage, aFlags);
     255                 :       }
     256                 :       return;
     257               0 :     } else if (aForChild == mInner.mHScrollbarBox) {
     258               0 :       if (!mInner.mHasHorizontalScrollbar) {
     259                 :         // Our scrollbars may send up invalidations even when they're collapsed,
     260                 :         // because we just size a collapsed scrollbar to empty and some
     261                 :         // descendants may be non-empty. Suppress that invalidation here.
     262               0 :         return;
     263                 :       }
     264               0 :     } else if (aForChild == mInner.mVScrollbarBox) {
     265               0 :       if (!mInner.mHasVerticalScrollbar) {
     266                 :         // Our scrollbars may send up invalidations even when they're collapsed,
     267                 :         // because we just size a collapsed scrollbar to empty and some
     268                 :         // descendants may be non-empty. Suppress that invalidation here.
     269               0 :         return;
     270                 :       }
     271                 :     }
     272                 :   }
     273                 :  
     274               0 :   nsContainerFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aFlags);
     275                 : }
     276                 : 
     277                 : /**
     278                 :  HTML scrolling implementation
     279                 : 
     280                 :  All other things being equal, we prefer layouts with fewer scrollbars showing.
     281                 : */
     282                 : 
     283               0 : struct ScrollReflowState {
     284                 :   const nsHTMLReflowState& mReflowState;
     285                 :   nsBoxLayoutState mBoxState;
     286                 :   nsGfxScrollFrameInner::ScrollbarStyles mStyles;
     287                 :   nsMargin mComputedBorder;
     288                 : 
     289                 :   // === Filled in by ReflowScrolledFrame ===
     290                 :   nsOverflowAreas mContentsOverflowAreas;
     291                 :   bool mReflowedContentsWithHScrollbar;
     292                 :   bool mReflowedContentsWithVScrollbar;
     293                 : 
     294                 :   // === Filled in when TryLayout succeeds ===
     295                 :   // The size of the inside-border area
     296                 :   nsSize mInsideBorderSize;
     297                 :   // Whether we decided to show the horizontal scrollbar
     298                 :   bool mShowHScrollbar;
     299                 :   // Whether we decided to show the vertical scrollbar
     300                 :   bool mShowVScrollbar;
     301                 : 
     302               0 :   ScrollReflowState(nsIScrollableFrame* aFrame,
     303                 :                     const nsHTMLReflowState& aState) :
     304                 :     mReflowState(aState),
     305                 :     // mBoxState is just used for scrollbars so we don't need to
     306                 :     // worry about the reflow depth here
     307                 :     mBoxState(aState.frame->PresContext(), aState.rendContext, 0),
     308               0 :     mStyles(aFrame->GetScrollbarStyles()) {
     309               0 :   }
     310                 : };
     311                 : 
     312                 : // XXXldb Can this go away?
     313               0 : static nsSize ComputeInsideBorderSize(ScrollReflowState* aState,
     314                 :                                       const nsSize& aDesiredInsideBorderSize)
     315                 : {
     316                 :   // aDesiredInsideBorderSize is the frame size; i.e., it includes
     317                 :   // borders and padding (but the scrolled child doesn't have
     318                 :   // borders). The scrolled child has the same padding as us.
     319               0 :   nscoord contentWidth = aState->mReflowState.ComputedWidth();
     320               0 :   if (contentWidth == NS_UNCONSTRAINEDSIZE) {
     321                 :     contentWidth = aDesiredInsideBorderSize.width -
     322               0 :       aState->mReflowState.mComputedPadding.LeftRight();
     323                 :   }
     324               0 :   nscoord contentHeight = aState->mReflowState.ComputedHeight();
     325               0 :   if (contentHeight == NS_UNCONSTRAINEDSIZE) {
     326                 :     contentHeight = aDesiredInsideBorderSize.height -
     327               0 :       aState->mReflowState.mComputedPadding.TopBottom();
     328                 :   }
     329                 : 
     330               0 :   aState->mReflowState.ApplyMinMaxConstraints(&contentWidth, &contentHeight);
     331               0 :   return nsSize(contentWidth + aState->mReflowState.mComputedPadding.LeftRight(),
     332               0 :                 contentHeight + aState->mReflowState.mComputedPadding.TopBottom());
     333                 : }
     334                 : 
     335                 : static void
     336               0 : GetScrollbarMetrics(nsBoxLayoutState& aState, nsIBox* aBox, nsSize* aMin,
     337                 :                     nsSize* aPref, bool aVertical)
     338                 : {
     339               0 :   NS_ASSERTION(aState.GetRenderingContext(),
     340                 :                "Must have rendering context in layout state for size "
     341                 :                "computations");
     342                 :   
     343               0 :   if (aMin) {
     344               0 :     *aMin = aBox->GetMinSize(aState);
     345               0 :     nsBox::AddMargin(aBox, *aMin);
     346                 :   }
     347                 :  
     348               0 :   if (aPref) {
     349               0 :     *aPref = aBox->GetPrefSize(aState);
     350               0 :     nsBox::AddMargin(aBox, *aPref);
     351                 :   }
     352               0 : }
     353                 : 
     354                 : /**
     355                 :  * Assuming that we know the metrics for our wrapped frame and
     356                 :  * whether the horizontal and/or vertical scrollbars are present,
     357                 :  * compute the resulting layout and return true if the layout is
     358                 :  * consistent. If the layout is consistent then we fill in the
     359                 :  * computed fields of the ScrollReflowState.
     360                 :  *
     361                 :  * The layout is consistent when both scrollbars are showing if and only
     362                 :  * if they should be showing. A horizontal scrollbar should be showing if all
     363                 :  * following conditions are met:
     364                 :  * 1) the style is not HIDDEN
     365                 :  * 2) our inside-border height is at least the scrollbar height (i.e., the
     366                 :  * scrollbar fits vertically)
     367                 :  * 3) our scrollport width (the inside-border width minus the width allocated for a
     368                 :  * vertical scrollbar, if showing) is at least the scrollbar's min-width
     369                 :  * (i.e., the scrollbar fits horizontally)
     370                 :  * 4) the style is SCROLL, or the kid's overflow-area XMost is
     371                 :  * greater than the scrollport width
     372                 :  *
     373                 :  * @param aForce if true, then we just assume the layout is consistent.
     374                 :  */
     375                 : bool
     376               0 : nsHTMLScrollFrame::TryLayout(ScrollReflowState* aState,
     377                 :                              nsHTMLReflowMetrics* aKidMetrics,
     378                 :                              bool aAssumeHScroll, bool aAssumeVScroll,
     379                 :                              bool aForce, nsresult* aResult)
     380                 : {
     381               0 :   *aResult = NS_OK;
     382                 : 
     383               0 :   if ((aState->mStyles.mVertical == NS_STYLE_OVERFLOW_HIDDEN && aAssumeVScroll) ||
     384                 :       (aState->mStyles.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN && aAssumeHScroll)) {
     385               0 :     NS_ASSERTION(!aForce, "Shouldn't be forcing a hidden scrollbar to show!");
     386               0 :     return false;
     387                 :   }
     388                 : 
     389               0 :   if (aAssumeVScroll != aState->mReflowedContentsWithVScrollbar ||
     390                 :       (aAssumeHScroll != aState->mReflowedContentsWithHScrollbar &&
     391               0 :        ScrolledContentDependsOnHeight(aState))) {
     392                 :     nsresult rv = ReflowScrolledFrame(aState, aAssumeHScroll, aAssumeVScroll,
     393               0 :                                       aKidMetrics, false);
     394               0 :     if (NS_FAILED(rv)) {
     395               0 :       *aResult = rv;
     396               0 :       return false;
     397                 :     }
     398                 :   }
     399                 : 
     400               0 :   nsSize vScrollbarMinSize(0, 0);
     401               0 :   nsSize vScrollbarPrefSize(0, 0);
     402               0 :   if (mInner.mVScrollbarBox) {
     403                 :     GetScrollbarMetrics(aState->mBoxState, mInner.mVScrollbarBox,
     404                 :                         &vScrollbarMinSize,
     405               0 :                         aAssumeVScroll ? &vScrollbarPrefSize : nsnull, true);
     406                 :   }
     407               0 :   nscoord vScrollbarDesiredWidth = aAssumeVScroll ? vScrollbarPrefSize.width : 0;
     408               0 :   nscoord vScrollbarMinHeight = aAssumeVScroll ? vScrollbarMinSize.height : 0;
     409                 : 
     410               0 :   nsSize hScrollbarMinSize(0, 0);
     411               0 :   nsSize hScrollbarPrefSize(0, 0);
     412               0 :   if (mInner.mHScrollbarBox) {
     413                 :     GetScrollbarMetrics(aState->mBoxState, mInner.mHScrollbarBox,
     414                 :                         &hScrollbarMinSize,
     415               0 :                         aAssumeHScroll ? &hScrollbarPrefSize : nsnull, false);
     416                 :   }
     417               0 :   nscoord hScrollbarDesiredHeight = aAssumeHScroll ? hScrollbarPrefSize.height : 0;
     418               0 :   nscoord hScrollbarMinWidth = aAssumeHScroll ? hScrollbarMinSize.width : 0;
     419                 : 
     420                 :   // First, compute our inside-border size and scrollport size
     421                 :   // XXXldb Can we depend more on ComputeSize here?
     422               0 :   nsSize desiredInsideBorderSize;
     423                 :   desiredInsideBorderSize.width = vScrollbarDesiredWidth +
     424               0 :     NS_MAX(aKidMetrics->width, hScrollbarMinWidth);
     425                 :   desiredInsideBorderSize.height = hScrollbarDesiredHeight +
     426               0 :     NS_MAX(aKidMetrics->height, vScrollbarMinHeight);
     427                 :   aState->mInsideBorderSize =
     428               0 :     ComputeInsideBorderSize(aState, desiredInsideBorderSize);
     429               0 :   nsSize scrollPortSize = nsSize(NS_MAX(0, aState->mInsideBorderSize.width - vScrollbarDesiredWidth),
     430               0 :                                  NS_MAX(0, aState->mInsideBorderSize.height - hScrollbarDesiredHeight));
     431                 : 
     432               0 :   if (!aForce) {
     433                 :     nsRect scrolledRect =
     434               0 :       mInner.GetScrolledRectInternal(aState->mContentsOverflowAreas.ScrollableOverflow(),
     435               0 :                                      scrollPortSize);
     436               0 :     nscoord oneDevPixel = aState->mBoxState.PresContext()->DevPixelsToAppUnits(1);
     437                 : 
     438                 :     // If the style is HIDDEN then we already know that aAssumeHScroll is false
     439               0 :     if (aState->mStyles.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN) {
     440                 :       bool wantHScrollbar =
     441                 :         aState->mStyles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL ||
     442               0 :         scrolledRect.XMost() >= scrollPortSize.width + oneDevPixel ||
     443               0 :         scrolledRect.x <= -oneDevPixel;
     444               0 :       if (scrollPortSize.width < hScrollbarMinSize.width)
     445               0 :         wantHScrollbar = false;
     446               0 :       if (wantHScrollbar != aAssumeHScroll)
     447               0 :         return false;
     448                 :     }
     449                 : 
     450                 :     // If the style is HIDDEN then we already know that aAssumeVScroll is false
     451               0 :     if (aState->mStyles.mVertical != NS_STYLE_OVERFLOW_HIDDEN) {
     452                 :       bool wantVScrollbar =
     453                 :         aState->mStyles.mVertical == NS_STYLE_OVERFLOW_SCROLL ||
     454               0 :         scrolledRect.YMost() >= scrollPortSize.height + oneDevPixel ||
     455               0 :         scrolledRect.y <= -oneDevPixel;
     456               0 :       if (scrollPortSize.height < vScrollbarMinSize.height)
     457               0 :         wantVScrollbar = false;
     458               0 :       if (wantVScrollbar != aAssumeVScroll)
     459               0 :         return false;
     460                 :     }
     461                 :   }
     462                 : 
     463               0 :   nscoord vScrollbarActualWidth = aState->mInsideBorderSize.width - scrollPortSize.width;
     464                 : 
     465               0 :   aState->mShowHScrollbar = aAssumeHScroll;
     466               0 :   aState->mShowVScrollbar = aAssumeVScroll;
     467                 :   nsPoint scrollPortOrigin(aState->mComputedBorder.left,
     468               0 :                            aState->mComputedBorder.top);
     469               0 :   if (!mInner.IsScrollbarOnRight()) {
     470               0 :     scrollPortOrigin.x += vScrollbarActualWidth;
     471                 :   }
     472               0 :   mInner.mScrollPort = nsRect(scrollPortOrigin, scrollPortSize);
     473               0 :   return true;
     474                 : }
     475                 : 
     476                 : bool
     477               0 : nsHTMLScrollFrame::ScrolledContentDependsOnHeight(ScrollReflowState* aState)
     478                 : {
     479                 :   // Return true if ReflowScrolledFrame is going to do something different
     480                 :   // based on the presence of a horizontal scrollbar.
     481               0 :   return (mInner.mScrolledFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT) ||
     482               0 :     aState->mReflowState.ComputedHeight() != NS_UNCONSTRAINEDSIZE ||
     483                 :     aState->mReflowState.mComputedMinHeight > 0 ||
     484               0 :     aState->mReflowState.mComputedMaxHeight != NS_UNCONSTRAINEDSIZE;
     485                 : }
     486                 : 
     487                 : nsresult
     488               0 : nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState,
     489                 :                                        bool aAssumeHScroll,
     490                 :                                        bool aAssumeVScroll,
     491                 :                                        nsHTMLReflowMetrics* aMetrics,
     492                 :                                        bool aFirstPass)
     493                 : {
     494                 :   // these could be NS_UNCONSTRAINEDSIZE ... NS_MIN arithmetic should
     495                 :   // be OK
     496               0 :   nscoord paddingLR = aState->mReflowState.mComputedPadding.LeftRight();
     497                 : 
     498               0 :   nscoord availWidth = aState->mReflowState.ComputedWidth() + paddingLR;
     499                 : 
     500               0 :   nscoord computedHeight = aState->mReflowState.ComputedHeight();
     501               0 :   nscoord computedMinHeight = aState->mReflowState.mComputedMinHeight;
     502               0 :   nscoord computedMaxHeight = aState->mReflowState.mComputedMaxHeight;
     503               0 :   if (!ShouldPropagateComputedHeightToScrolledContent()) {
     504               0 :     computedHeight = NS_UNCONSTRAINEDSIZE;
     505               0 :     computedMinHeight = 0;
     506               0 :     computedMaxHeight = NS_UNCONSTRAINEDSIZE;
     507                 :   }
     508               0 :   if (aAssumeHScroll) {
     509                 :     nsSize hScrollbarPrefSize = 
     510               0 :       mInner.mHScrollbarBox->GetPrefSize(const_cast<nsBoxLayoutState&>(aState->mBoxState));
     511               0 :     if (computedHeight != NS_UNCONSTRAINEDSIZE)
     512               0 :       computedHeight = NS_MAX(0, computedHeight - hScrollbarPrefSize.height);
     513               0 :     computedMinHeight = NS_MAX(0, computedMinHeight - hScrollbarPrefSize.height);
     514               0 :     if (computedMaxHeight != NS_UNCONSTRAINEDSIZE)
     515               0 :       computedMaxHeight = NS_MAX(0, computedMaxHeight - hScrollbarPrefSize.height);
     516                 :   }
     517                 : 
     518               0 :   if (aAssumeVScroll) {
     519                 :     nsSize vScrollbarPrefSize = 
     520               0 :       mInner.mVScrollbarBox->GetPrefSize(const_cast<nsBoxLayoutState&>(aState->mBoxState));
     521               0 :     availWidth = NS_MAX(0, availWidth - vScrollbarPrefSize.width);
     522                 :   }
     523                 : 
     524               0 :   nsPresContext* presContext = PresContext();
     525                 : 
     526                 :   // Pass false for aInit so we can pass in the correct padding.
     527                 :   nsHTMLReflowState kidReflowState(presContext, aState->mReflowState,
     528                 :                                    mInner.mScrolledFrame,
     529                 :                                    nsSize(availWidth, NS_UNCONSTRAINEDSIZE),
     530               0 :                                    -1, -1, false);
     531                 :   kidReflowState.Init(presContext, -1, -1, nsnull,
     532               0 :                       &aState->mReflowState.mComputedPadding);
     533               0 :   kidReflowState.mFlags.mAssumingHScrollbar = aAssumeHScroll;
     534               0 :   kidReflowState.mFlags.mAssumingVScrollbar = aAssumeVScroll;
     535               0 :   kidReflowState.SetComputedHeight(computedHeight);
     536               0 :   kidReflowState.mComputedMinHeight = computedMinHeight;
     537               0 :   kidReflowState.mComputedMaxHeight = computedMaxHeight;
     538                 : 
     539                 :   // Temporarily set mHasHorizontalScrollbar/mHasVerticalScrollbar to
     540                 :   // reflect our assumptions while we reflow the child.
     541               0 :   bool didHaveHorizontalScrollbar = mInner.mHasHorizontalScrollbar;
     542               0 :   bool didHaveVerticalScrollbar = mInner.mHasVerticalScrollbar;
     543               0 :   mInner.mHasHorizontalScrollbar = aAssumeHScroll;
     544               0 :   mInner.mHasVerticalScrollbar = aAssumeVScroll;
     545                 : 
     546                 :   nsReflowStatus status;
     547                 :   nsresult rv = ReflowChild(mInner.mScrolledFrame, presContext, *aMetrics,
     548                 :                             kidReflowState, 0, 0,
     549               0 :                             NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_MOVE_VIEW, status);
     550                 : 
     551               0 :   mInner.mHasHorizontalScrollbar = didHaveHorizontalScrollbar;
     552               0 :   mInner.mHasVerticalScrollbar = didHaveVerticalScrollbar;
     553                 : 
     554                 :   // Don't resize or position the view (if any) because we're going to resize
     555                 :   // it to the correct size anyway in PlaceScrollArea. Allowing it to
     556                 :   // resize here would size it to the natural height of the frame,
     557                 :   // which will usually be different from the scrollport height;
     558                 :   // invalidating the difference will cause unnecessary repainting.
     559                 :   FinishReflowChild(mInner.mScrolledFrame, presContext,
     560                 :                     &kidReflowState, *aMetrics, 0, 0,
     561               0 :                     NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_MOVE_VIEW | NS_FRAME_NO_SIZE_VIEW);
     562                 : 
     563                 :   // XXX Some frames (e.g., nsObjectFrame, nsFrameFrame, nsTextFrame) don't bother
     564                 :   // setting their mOverflowArea. This is wrong because every frame should
     565                 :   // always set mOverflowArea. In fact nsObjectFrame and nsFrameFrame don't
     566                 :   // support the 'outline' property because of this. Rather than fix the world
     567                 :   // right now, just fix up the overflow area if necessary. Note that we don't
     568                 :   // check HasOverflowRect() because it could be set even though the
     569                 :   // overflow area doesn't include the frame bounds.
     570               0 :   aMetrics->UnionOverflowAreasWithDesiredBounds();
     571                 : 
     572               0 :   aState->mContentsOverflowAreas = aMetrics->mOverflowAreas;
     573               0 :   aState->mReflowedContentsWithHScrollbar = aAssumeHScroll;
     574               0 :   aState->mReflowedContentsWithVScrollbar = aAssumeVScroll;
     575                 :   
     576               0 :   return rv;
     577                 : }
     578                 : 
     579                 : bool
     580               0 : nsHTMLScrollFrame::GuessHScrollbarNeeded(const ScrollReflowState& aState)
     581                 : {
     582               0 :   if (aState.mStyles.mHorizontal != NS_STYLE_OVERFLOW_AUTO)
     583                 :     // no guessing required
     584               0 :     return aState.mStyles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL;
     585                 : 
     586               0 :   return mInner.mHasHorizontalScrollbar;
     587                 : }
     588                 : 
     589                 : bool
     590               0 : nsHTMLScrollFrame::GuessVScrollbarNeeded(const ScrollReflowState& aState)
     591                 : {
     592               0 :   if (aState.mStyles.mVertical != NS_STYLE_OVERFLOW_AUTO)
     593                 :     // no guessing required
     594               0 :     return aState.mStyles.mVertical == NS_STYLE_OVERFLOW_SCROLL;
     595                 : 
     596                 :   // If we've had at least one non-initial reflow, then just assume
     597                 :   // the state of the vertical scrollbar will be what we determined
     598                 :   // last time.
     599               0 :   if (mInner.mHadNonInitialReflow) {
     600               0 :     return mInner.mHasVerticalScrollbar;
     601                 :   }
     602                 : 
     603                 :   // If this is the initial reflow, guess false because usually
     604                 :   // we have very little content by then.
     605               0 :   if (InInitialReflow())
     606               0 :     return false;
     607                 : 
     608               0 :   if (mInner.mIsRoot) {
     609                 :     // Assume that there will be a scrollbar; it seems to me
     610                 :     // that 'most pages' do have a scrollbar, and anyway, it's cheaper
     611                 :     // to do an extra reflow for the pages that *don't* need a
     612                 :     // scrollbar (because on average they will have less content).
     613               0 :     return true;
     614                 :   }
     615                 : 
     616                 :   // For non-viewports, just guess that we don't need a scrollbar.
     617                 :   // XXX I wonder if statistically this is the right idea; I'm
     618                 :   // basically guessing that there are a lot of overflow:auto DIVs
     619                 :   // that get their intrinsic size and don't overflow
     620               0 :   return false;
     621                 : }
     622                 : 
     623                 : bool
     624               0 : nsHTMLScrollFrame::InInitialReflow() const
     625                 : {
     626                 :   // We're in an initial reflow if NS_FRAME_FIRST_REFLOW is set, unless we're a
     627                 :   // root scrollframe.  In that case we want to skip this clause altogether.
     628                 :   // The guess here is that there are lots of overflow:auto divs out there that
     629                 :   // end up auto-sizing so they don't overflow, and that the root basically
     630                 :   // always needs a scrollbar if it did last time we loaded this page (good
     631                 :   // assumption, because our initial reflow is no longer synchronous).
     632               0 :   return !mInner.mIsRoot && (GetStateBits() & NS_FRAME_FIRST_REFLOW);
     633                 : }
     634                 : 
     635                 : nsresult
     636               0 : nsHTMLScrollFrame::ReflowContents(ScrollReflowState* aState,
     637                 :                                   const nsHTMLReflowMetrics& aDesiredSize)
     638                 : {
     639               0 :   nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mFlags);
     640               0 :   nsresult rv = ReflowScrolledFrame(aState, GuessHScrollbarNeeded(*aState),
     641               0 :       GuessVScrollbarNeeded(*aState), &kidDesiredSize, true);
     642               0 :   NS_ENSURE_SUCCESS(rv, rv);
     643                 : 
     644                 :   // There's an important special case ... if the child appears to fit
     645                 :   // in the inside-border rect (but overflows the scrollport), we
     646                 :   // should try laying it out without a vertical scrollbar. It will
     647                 :   // usually fit because making the available-width wider will not
     648                 :   // normally make the child taller. (The only situation I can think
     649                 :   // of is when you have a line containing %-width inline replaced
     650                 :   // elements whose percentages sum to more than 100%, so increasing
     651                 :   // the available width makes the line break where it was fitting
     652                 :   // before.) If we don't treat this case specially, then we will
     653                 :   // decide that showing scrollbars is OK because the content
     654                 :   // overflows when we're showing scrollbars and we won't try to
     655                 :   // remove the vertical scrollbar.
     656                 : 
     657                 :   // Detecting when we enter this special case is important for when
     658                 :   // people design layouts that exactly fit the container "most of the
     659                 :   // time".
     660                 : 
     661                 :   // XXX Is this check really sufficient to catch all the incremental cases
     662                 :   // where the ideal case doesn't have a scrollbar?
     663               0 :   if ((aState->mReflowedContentsWithHScrollbar || aState->mReflowedContentsWithVScrollbar) &&
     664                 :       aState->mStyles.mVertical != NS_STYLE_OVERFLOW_SCROLL &&
     665                 :       aState->mStyles.mHorizontal != NS_STYLE_OVERFLOW_SCROLL) {
     666                 :     nsSize insideBorderSize =
     667                 :       ComputeInsideBorderSize(aState,
     668               0 :                               nsSize(kidDesiredSize.width, kidDesiredSize.height));
     669                 :     nsRect scrolledRect =
     670               0 :       mInner.GetScrolledRectInternal(kidDesiredSize.ScrollableOverflow(),
     671               0 :                                      insideBorderSize);
     672               0 :     if (nsRect(nsPoint(0, 0), insideBorderSize).Contains(scrolledRect)) {
     673                 :       // Let's pretend we had no scrollbars coming in here
     674                 :       rv = ReflowScrolledFrame(aState, false, false,
     675               0 :                                &kidDesiredSize, false);
     676               0 :       NS_ENSURE_SUCCESS(rv, rv);
     677                 :     }
     678                 :   }
     679                 : 
     680                 :   // Try vertical scrollbar settings that leave the vertical scrollbar unchanged.
     681                 :   // Do this first because changing the vertical scrollbar setting is expensive,
     682                 :   // forcing a reflow always.
     683                 : 
     684                 :   // Try leaving the horizontal scrollbar unchanged first. This will be more
     685                 :   // efficient.
     686               0 :   if (TryLayout(aState, &kidDesiredSize, aState->mReflowedContentsWithHScrollbar,
     687               0 :                 aState->mReflowedContentsWithVScrollbar, false, &rv))
     688               0 :     return NS_OK;
     689               0 :   if (TryLayout(aState, &kidDesiredSize, !aState->mReflowedContentsWithHScrollbar,
     690               0 :                 aState->mReflowedContentsWithVScrollbar, false, &rv))
     691               0 :     return NS_OK;
     692                 : 
     693                 :   // OK, now try toggling the vertical scrollbar. The performance advantage
     694                 :   // of trying the status-quo horizontal scrollbar state
     695                 :   // does not exist here (we'll have to reflow due to the vertical scrollbar
     696                 :   // change), so always try no horizontal scrollbar first.
     697               0 :   bool newVScrollbarState = !aState->mReflowedContentsWithVScrollbar;
     698               0 :   if (TryLayout(aState, &kidDesiredSize, false, newVScrollbarState, false, &rv))
     699               0 :     return NS_OK;
     700               0 :   if (TryLayout(aState, &kidDesiredSize, true, newVScrollbarState, false, &rv))
     701               0 :     return NS_OK;
     702                 : 
     703                 :   // OK, we're out of ideas. Try again enabling whatever scrollbars we can
     704                 :   // enable and force the layout to stick even if it's inconsistent.
     705                 :   // This just happens sometimes.
     706                 :   TryLayout(aState, &kidDesiredSize,
     707                 :             aState->mStyles.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN,
     708                 :             aState->mStyles.mVertical != NS_STYLE_OVERFLOW_HIDDEN,
     709               0 :             true, &rv);
     710               0 :   return rv;
     711                 : }
     712                 : 
     713                 : void
     714               0 : nsHTMLScrollFrame::PlaceScrollArea(const ScrollReflowState& aState,
     715                 :                                    const nsPoint& aScrollPosition)
     716                 : {
     717               0 :   nsIFrame *scrolledFrame = mInner.mScrolledFrame;
     718                 :   // Set the x,y of the scrolled frame to the correct value
     719               0 :   scrolledFrame->SetPosition(mInner.mScrollPort.TopLeft() - aScrollPosition);
     720                 : 
     721               0 :   nsRect scrolledArea;
     722                 :   // Preserve the width or height of empty rects
     723               0 :   nsSize portSize = mInner.mScrollPort.Size();
     724                 :   nsRect scrolledRect =
     725               0 :     mInner.GetScrolledRectInternal(aState.mContentsOverflowAreas.ScrollableOverflow(),
     726               0 :                                    portSize);
     727                 :   scrolledArea.UnionRectEdges(scrolledRect,
     728               0 :                               nsRect(nsPoint(0,0), portSize));
     729                 : 
     730                 :   // Store the new overflow area. Note that this changes where an outline
     731                 :   // of the scrolled frame would be painted, but scrolled frames can't have
     732                 :   // outlines (the outline would go on this scrollframe instead).
     733                 :   // Using FinishAndStoreOverflow is needed so the overflow rect
     734                 :   // gets set correctly.  It also messes with the overflow rect in the
     735                 :   // -moz-hidden-unscrollable case, but scrolled frames can't have
     736                 :   // 'overflow' either.
     737                 :   // This needs to happen before SyncFrameViewAfterReflow so
     738                 :   // HasOverflowRect() will return the correct value.
     739               0 :   nsOverflowAreas overflow(scrolledArea, scrolledArea);
     740                 :   scrolledFrame->FinishAndStoreOverflow(overflow,
     741               0 :                                         scrolledFrame->GetSize());
     742                 : 
     743                 :   // Note that making the view *exactly* the size of the scrolled area
     744                 :   // is critical, since the view scrolling code uses the size of the
     745                 :   // scrolled view to clamp scroll requests.
     746                 :   // Normally the scrolledFrame won't have a view but in some cases it
     747                 :   // might create its own.
     748                 :   nsContainerFrame::SyncFrameViewAfterReflow(scrolledFrame->PresContext(),
     749                 :                                              scrolledFrame,
     750                 :                                              scrolledFrame->GetView(),
     751                 :                                              scrolledArea,
     752               0 :                                              0);
     753               0 : }
     754                 : 
     755                 : nscoord
     756               0 : nsHTMLScrollFrame::GetIntrinsicVScrollbarWidth(nsRenderingContext *aRenderingContext)
     757                 : {
     758               0 :   nsGfxScrollFrameInner::ScrollbarStyles ss = GetScrollbarStyles();
     759               0 :   if (ss.mVertical != NS_STYLE_OVERFLOW_SCROLL || !mInner.mVScrollbarBox)
     760               0 :     return 0;
     761                 : 
     762                 :   // Don't need to worry about reflow depth here since it's
     763                 :   // just for scrollbars
     764               0 :   nsBoxLayoutState bls(PresContext(), aRenderingContext, 0);
     765               0 :   nsSize vScrollbarPrefSize(0, 0);
     766                 :   GetScrollbarMetrics(bls, mInner.mVScrollbarBox,
     767               0 :                       nsnull, &vScrollbarPrefSize, true);
     768               0 :   return vScrollbarPrefSize.width;
     769                 : }
     770                 : 
     771                 : /* virtual */ nscoord
     772               0 : nsHTMLScrollFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
     773                 : {
     774               0 :   nscoord result = mInner.mScrolledFrame->GetMinWidth(aRenderingContext);
     775               0 :   DISPLAY_MIN_WIDTH(this, result);
     776               0 :   return result + GetIntrinsicVScrollbarWidth(aRenderingContext);
     777                 : }
     778                 : 
     779                 : /* virtual */ nscoord
     780               0 : nsHTMLScrollFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
     781                 : {
     782               0 :   nscoord result = mInner.mScrolledFrame->GetPrefWidth(aRenderingContext);
     783               0 :   DISPLAY_PREF_WIDTH(this, result);
     784               0 :   return NSCoordSaturatingAdd(result, GetIntrinsicVScrollbarWidth(aRenderingContext));
     785                 : }
     786                 : 
     787                 : NS_IMETHODIMP
     788               0 : nsHTMLScrollFrame::GetPadding(nsMargin& aMargin)
     789                 : {
     790                 :   // Our padding hangs out on the inside of the scrollframe, but XUL doesn't
     791                 :   // reaize that.  If we're stuck inside a XUL box, we need to claim no
     792                 :   // padding.
     793                 :   // @see also nsXULScrollFrame::GetPadding.
     794               0 :   aMargin.SizeTo(0,0,0,0);
     795               0 :   return NS_OK;
     796                 : }
     797                 : 
     798                 : bool
     799               0 : nsHTMLScrollFrame::IsCollapsed()
     800                 : {
     801                 :   // We're never collapsed in the box sense.
     802               0 :   return false;
     803                 : }
     804                 : 
     805                 : // Return the <browser> if the scrollframe is for the root frame directly
     806                 : // inside a <browser>.
     807                 : static nsIContent*
     808               0 : GetBrowserRoot(nsIContent* aContent)
     809                 : {
     810               0 :   if (aContent) {
     811               0 :     nsIDocument* doc = aContent->GetCurrentDoc();
     812               0 :     nsPIDOMWindow* win = doc->GetWindow();
     813               0 :     if (win) {
     814                 :       nsCOMPtr<nsIContent> frameContent =
     815               0 :         do_QueryInterface(win->GetFrameElementInternal());
     816               0 :       if (frameContent &&
     817               0 :           frameContent->NodeInfo()->Equals(nsGkAtoms::browser, kNameSpaceID_XUL))
     818               0 :         return frameContent;
     819                 :     }
     820                 :   }
     821                 : 
     822               0 :   return nsnull;
     823                 : }
     824                 : 
     825                 : 
     826                 : NS_IMETHODIMP
     827               0 : nsHTMLScrollFrame::Reflow(nsPresContext*           aPresContext,
     828                 :                           nsHTMLReflowMetrics&     aDesiredSize,
     829                 :                           const nsHTMLReflowState& aReflowState,
     830                 :                           nsReflowStatus&          aStatus)
     831                 : {
     832               0 :   DO_GLOBAL_REFLOW_COUNT("nsHTMLScrollFrame");
     833               0 :   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
     834                 : 
     835               0 :   ScrollReflowState state(this, aReflowState);
     836                 :   // sanity check: ensure that if we have no scrollbar, we treat it
     837                 :   // as hidden.
     838               0 :   if (!mInner.mVScrollbarBox || mInner.mNeverHasVerticalScrollbar)
     839               0 :     state.mStyles.mVertical = NS_STYLE_OVERFLOW_HIDDEN;
     840               0 :   if (!mInner.mHScrollbarBox || mInner.mNeverHasHorizontalScrollbar)
     841               0 :     state.mStyles.mHorizontal = NS_STYLE_OVERFLOW_HIDDEN;
     842                 : 
     843                 :   //------------ Handle Incremental Reflow -----------------
     844               0 :   bool reflowHScrollbar = true;
     845               0 :   bool reflowVScrollbar = true;
     846               0 :   bool reflowScrollCorner = true;
     847               0 :   if (!aReflowState.ShouldReflowAllKids()) {
     848                 :     #define NEEDS_REFLOW(frame_) \
     849                 :       ((frame_) && NS_SUBTREE_DIRTY(frame_))
     850                 : 
     851               0 :     reflowHScrollbar = NEEDS_REFLOW(mInner.mHScrollbarBox);
     852               0 :     reflowVScrollbar = NEEDS_REFLOW(mInner.mVScrollbarBox);
     853               0 :     reflowScrollCorner = NEEDS_REFLOW(mInner.mScrollCornerBox) ||
     854               0 :                          NEEDS_REFLOW(mInner.mResizerBox);
     855                 : 
     856                 :     #undef NEEDS_REFLOW
     857                 :   }
     858                 : 
     859               0 :   if (mInner.mIsRoot) {
     860               0 :     mInner.mCollapsedResizer = true;
     861                 : 
     862               0 :     nsIContent* browserRoot = GetBrowserRoot(mContent);
     863               0 :     if (browserRoot) {
     864               0 :       bool showResizer = browserRoot->HasAttr(kNameSpaceID_None, nsGkAtoms::showresizer);
     865               0 :       reflowScrollCorner = showResizer == mInner.mCollapsedResizer;
     866               0 :       mInner.mCollapsedResizer = !showResizer;
     867                 :     }
     868                 :   }
     869                 : 
     870               0 :   nsRect oldScrollAreaBounds = mInner.mScrollPort;
     871                 :   nsRect oldScrolledAreaBounds =
     872               0 :     mInner.mScrolledFrame->GetScrollableOverflowRectRelativeToParent();
     873                 :   // Adjust to a multiple of device pixels to restore the invariant that
     874                 :   // oldScrollPosition is a multiple of device pixels. This could have been
     875                 :   // thrown out by a zoom change.
     876               0 :   nsIntPoint ptDevPx;
     877               0 :   nsPoint oldScrollPosition = mInner.GetScrollPosition();
     878                 :   
     879                 :   state.mComputedBorder = aReflowState.mComputedBorderPadding -
     880               0 :     aReflowState.mComputedPadding;
     881                 : 
     882               0 :   nsresult rv = ReflowContents(&state, aDesiredSize);
     883               0 :   if (NS_FAILED(rv))
     884               0 :     return rv;
     885                 : 
     886                 :   // Restore the old scroll position, for now, even if that's not valid anymore
     887                 :   // because we changed size. We'll fix it up in a post-reflow callback, because
     888                 :   // our current size may only be temporary (e.g. we're compute XUL desired sizes).
     889               0 :   PlaceScrollArea(state, oldScrollPosition);
     890               0 :   if (!mInner.mPostedReflowCallback) {
     891                 :     // Make sure we'll try scrolling to restored position
     892               0 :     PresContext()->PresShell()->PostReflowCallback(&mInner);
     893               0 :     mInner.mPostedReflowCallback = true;
     894                 :   }
     895                 : 
     896               0 :   bool didHaveHScrollbar = mInner.mHasHorizontalScrollbar;
     897               0 :   bool didHaveVScrollbar = mInner.mHasVerticalScrollbar;
     898               0 :   mInner.mHasHorizontalScrollbar = state.mShowHScrollbar;
     899               0 :   mInner.mHasVerticalScrollbar = state.mShowVScrollbar;
     900               0 :   nsRect newScrollAreaBounds = mInner.mScrollPort;
     901                 :   nsRect newScrolledAreaBounds =
     902               0 :     mInner.mScrolledFrame->GetScrollableOverflowRectRelativeToParent();
     903               0 :   if (mInner.mSkippedScrollbarLayout ||
     904                 :       reflowHScrollbar || reflowVScrollbar || reflowScrollCorner ||
     905               0 :       (GetStateBits() & NS_FRAME_IS_DIRTY) ||
     906                 :       didHaveHScrollbar != state.mShowHScrollbar ||
     907                 :       didHaveVScrollbar != state.mShowVScrollbar ||
     908               0 :       !oldScrollAreaBounds.IsEqualEdges(newScrollAreaBounds) ||
     909               0 :       !oldScrolledAreaBounds.IsEqualEdges(newScrolledAreaBounds)) {
     910               0 :     if (!mInner.mSupppressScrollbarUpdate) {
     911               0 :       mInner.mSkippedScrollbarLayout = false;
     912               0 :       mInner.SetScrollbarVisibility(mInner.mHScrollbarBox, state.mShowHScrollbar);
     913               0 :       mInner.SetScrollbarVisibility(mInner.mVScrollbarBox, state.mShowVScrollbar);
     914                 :       // place and reflow scrollbars
     915                 :       nsRect insideBorderArea =
     916                 :         nsRect(nsPoint(state.mComputedBorder.left, state.mComputedBorder.top),
     917               0 :                state.mInsideBorderSize);
     918                 :       mInner.LayoutScrollbars(state.mBoxState, insideBorderArea,
     919               0 :                               oldScrollAreaBounds);
     920                 :     } else {
     921               0 :       mInner.mSkippedScrollbarLayout = true;
     922                 :     }
     923                 :   }
     924                 : 
     925                 :   aDesiredSize.width = state.mInsideBorderSize.width +
     926               0 :     state.mComputedBorder.LeftRight();
     927                 :   aDesiredSize.height = state.mInsideBorderSize.height +
     928               0 :     state.mComputedBorder.TopBottom();
     929                 : 
     930               0 :   aDesiredSize.SetOverflowAreasToDesiredBounds();
     931               0 :   if (mInner.IsIgnoringViewportClipping()) {
     932                 :     aDesiredSize.mOverflowAreas.UnionWith(
     933               0 :       state.mContentsOverflowAreas + mInner.mScrolledFrame->GetPosition());
     934                 :   }
     935                 : 
     936               0 :   CheckInvalidateSizeChange(aDesiredSize);
     937                 : 
     938               0 :   FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
     939                 : 
     940               0 :   if (!InInitialReflow() && !mInner.mHadNonInitialReflow) {
     941               0 :     mInner.mHadNonInitialReflow = true;
     942                 :   }
     943                 : 
     944               0 :   if (mInner.mIsRoot && !oldScrolledAreaBounds.IsEqualEdges(newScrolledAreaBounds)) {
     945               0 :     mInner.PostScrolledAreaEvent();
     946                 :   }
     947                 : 
     948               0 :   aStatus = NS_FRAME_COMPLETE;
     949               0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
     950               0 :   mInner.PostOverflowEvent();
     951               0 :   return rv;
     952                 : }
     953                 : 
     954                 : 
     955                 : ////////////////////////////////////////////////////////////////////////////////
     956                 : 
     957                 : #ifdef NS_DEBUG
     958                 : NS_IMETHODIMP
     959               0 : nsHTMLScrollFrame::GetFrameName(nsAString& aResult) const
     960                 : {
     961               0 :   return MakeFrameName(NS_LITERAL_STRING("HTMLScroll"), aResult);
     962                 : }
     963                 : #endif
     964                 : 
     965                 : #ifdef ACCESSIBILITY
     966                 : already_AddRefed<nsAccessible>
     967               0 : nsHTMLScrollFrame::CreateAccessible()
     968                 : {
     969                 :   // Create an accessible regardless of focusable state because the state can be
     970                 :   // changed during frame life cycle without any notifications to accessibility.
     971               0 :   if (mContent->IsRootOfNativeAnonymousSubtree() ||
     972               0 :       GetScrollbarStyles() == nsIScrollableFrame::
     973               0 :         ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN) ) {
     974               0 :     return nsnull;
     975                 :   }
     976                 : 
     977               0 :   nsAccessibilityService* accService = nsIPresShell::AccService();
     978               0 :   if (accService) {
     979                 :     return accService->CreateHyperTextAccessible(mContent,
     980               0 :                                                  PresContext()->PresShell());
     981                 :   }
     982                 : 
     983               0 :   return nsnull;
     984                 : }
     985                 : #endif
     986                 : 
     987               0 : NS_QUERYFRAME_HEAD(nsHTMLScrollFrame)
     988               0 :   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
     989               0 :   NS_QUERYFRAME_ENTRY(nsIScrollableFrame)
     990               0 :   NS_QUERYFRAME_ENTRY(nsIStatefulFrame)
     991               0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
     992                 : 
     993                 : //----------nsXULScrollFrame-------------------------------------------
     994                 : 
     995                 : nsIFrame*
     996               0 : NS_NewXULScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot)
     997                 : {
     998               0 :   return new (aPresShell) nsXULScrollFrame(aPresShell, aContext, aIsRoot);
     999                 : }
    1000                 : 
    1001               0 : NS_IMPL_FRAMEARENA_HELPERS(nsXULScrollFrame)
    1002                 : 
    1003               0 : nsXULScrollFrame::nsXULScrollFrame(nsIPresShell* aShell, nsStyleContext* aContext, bool aIsRoot)
    1004                 :   : nsBoxFrame(aShell, aContext, aIsRoot),
    1005               0 :     mInner(this, aIsRoot)
    1006                 : {
    1007               0 :     SetLayoutManager(nsnull);
    1008               0 : }
    1009                 : 
    1010               0 : nsMargin nsGfxScrollFrameInner::GetDesiredScrollbarSizes(nsBoxLayoutState* aState) {
    1011               0 :   NS_ASSERTION(aState && aState->GetRenderingContext(),
    1012                 :                "Must have rendering context in layout state for size "
    1013                 :                "computations");
    1014                 :   
    1015               0 :   nsMargin result(0, 0, 0, 0);
    1016                 : 
    1017               0 :   if (mVScrollbarBox) {
    1018               0 :     nsSize size = mVScrollbarBox->GetPrefSize(*aState);
    1019               0 :     nsBox::AddMargin(mVScrollbarBox, size);
    1020               0 :     if (IsScrollbarOnRight())
    1021               0 :       result.left = size.width;
    1022                 :     else
    1023               0 :       result.right = size.width;
    1024                 :   }
    1025                 : 
    1026               0 :   if (mHScrollbarBox) {
    1027               0 :     nsSize size = mHScrollbarBox->GetPrefSize(*aState);
    1028               0 :     nsBox::AddMargin(mHScrollbarBox, size);
    1029                 :     // We don't currently support any scripts that would require a scrollbar
    1030                 :     // at the top. (Are there any?)
    1031               0 :     result.bottom = size.height;
    1032                 :   }
    1033                 : 
    1034                 :   return result;
    1035                 : }
    1036                 : 
    1037                 : nsresult
    1038               0 : nsXULScrollFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
    1039                 : {
    1040               0 :   return mInner.CreateAnonymousContent(aElements);
    1041                 : }
    1042                 : 
    1043                 : void
    1044               0 : nsXULScrollFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
    1045                 :                                            PRUint32 aFilter)
    1046                 : {
    1047               0 :   mInner.AppendAnonymousContentTo(aElements, aFilter);
    1048               0 : }
    1049                 : 
    1050                 : void
    1051               0 : nsXULScrollFrame::DestroyFrom(nsIFrame* aDestructRoot)
    1052                 : {
    1053               0 :   mInner.Destroy();
    1054               0 :   nsBoxFrame::DestroyFrom(aDestructRoot);
    1055               0 : }
    1056                 : 
    1057                 : NS_IMETHODIMP
    1058               0 : nsXULScrollFrame::SetInitialChildList(ChildListID     aListID,
    1059                 :                                       nsFrameList&    aChildList)
    1060                 : {
    1061               0 :   nsresult rv = nsBoxFrame::SetInitialChildList(aListID, aChildList);
    1062               0 :   mInner.ReloadChildFrames();
    1063               0 :   return rv;
    1064                 : }
    1065                 : 
    1066                 : 
    1067                 : NS_IMETHODIMP
    1068               0 : nsXULScrollFrame::AppendFrames(ChildListID     aListID,
    1069                 :                                nsFrameList&    aFrameList)
    1070                 : {
    1071               0 :   nsresult rv = nsBoxFrame::AppendFrames(aListID, aFrameList);
    1072               0 :   mInner.ReloadChildFrames();
    1073               0 :   return rv;
    1074                 : }
    1075                 : 
    1076                 : NS_IMETHODIMP
    1077               0 : nsXULScrollFrame::InsertFrames(ChildListID     aListID,
    1078                 :                                nsIFrame*       aPrevFrame,
    1079                 :                                nsFrameList&    aFrameList)
    1080                 : {
    1081               0 :   nsresult rv = nsBoxFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
    1082               0 :   mInner.ReloadChildFrames();
    1083               0 :   return rv;
    1084                 : }
    1085                 : 
    1086                 : NS_IMETHODIMP
    1087               0 : nsXULScrollFrame::RemoveFrame(ChildListID     aListID,
    1088                 :                               nsIFrame*       aOldFrame)
    1089                 : {
    1090               0 :   nsresult rv = nsBoxFrame::RemoveFrame(aListID, aOldFrame);
    1091               0 :   mInner.ReloadChildFrames();
    1092               0 :   return rv;
    1093                 : }
    1094                 : 
    1095                 : nsSplittableType
    1096               0 : nsXULScrollFrame::GetSplittableType() const
    1097                 : {
    1098               0 :   return NS_FRAME_NOT_SPLITTABLE;
    1099                 : }
    1100                 : 
    1101                 : NS_IMETHODIMP
    1102               0 : nsXULScrollFrame::GetPadding(nsMargin& aMargin)
    1103                 : {
    1104               0 :    aMargin.SizeTo(0,0,0,0);
    1105               0 :    return NS_OK;
    1106                 : }
    1107                 : 
    1108                 : PRIntn
    1109               0 : nsXULScrollFrame::GetSkipSides() const
    1110                 : {
    1111               0 :   return 0;
    1112                 : }
    1113                 : 
    1114                 : nsIAtom*
    1115               0 : nsXULScrollFrame::GetType() const
    1116                 : {
    1117               0 :   return nsGkAtoms::scrollFrame; 
    1118                 : }
    1119                 : 
    1120                 : void
    1121               0 : nsXULScrollFrame::InvalidateInternal(const nsRect& aDamageRect,
    1122                 :                                      nscoord aX, nscoord aY, nsIFrame* aForChild,
    1123                 :                                      PRUint32 aFlags)
    1124                 : {
    1125               0 :   if (aForChild == mInner.mScrolledFrame) {
    1126               0 :     nsRect damage = aDamageRect + nsPoint(aX, aY);
    1127                 :     // This is the damage rect that we're going to pass up to our parent.
    1128               0 :     nsRect parentDamage;
    1129                 :     // If we're using a displayport, we might be displaying an area
    1130                 :     // different than our scroll port and the damage needs to be
    1131                 :     // clipped to that instead.
    1132               0 :     nsRect displayport;
    1133                 :     bool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(),
    1134               0 :                                                             &displayport);
    1135               0 :     if (usingDisplayport) {
    1136               0 :       parentDamage.IntersectRect(damage, displayport);
    1137                 :     } else {
    1138               0 :       parentDamage.IntersectRect(damage, mInner.mScrollPort);
    1139                 :     }
    1140                 : 
    1141               0 :     if (IsScrollingActive()) {
    1142                 :       // This is the damage rect that we're going to pass up and
    1143                 :       // only request invalidation of ThebesLayers for.
    1144                 :       // damage is now in our coordinate system, which means it was
    1145                 :       // translated using the current scroll position. Adjust it to
    1146                 :       // reflect the scroll position at last paint, since that's what
    1147                 :       // the ThebesLayers are currently set up for.
    1148                 :       // This should not be clipped to the scrollport since ThebesLayers
    1149                 :       // can contain content outside the scrollport that may need to be
    1150                 :       // invalidated.
    1151               0 :       nsRect thebesLayerDamage = damage + GetScrollPosition() - mInner.mScrollPosAtLastPaint;
    1152               0 :       if (parentDamage.IsEqualInterior(thebesLayerDamage)) {
    1153                 :         // This single call will take care of both rects
    1154               0 :         nsBoxFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags);
    1155                 :       } else {
    1156                 :         // Invalidate rects separately
    1157               0 :         if (!(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
    1158                 :           nsBoxFrame::InvalidateInternal(thebesLayerDamage, 0, 0, aForChild,
    1159               0 :                                          aFlags | INVALIDATE_ONLY_THEBES_LAYERS);
    1160                 :         }
    1161               0 :         if (!(aFlags & INVALIDATE_ONLY_THEBES_LAYERS) && !parentDamage.IsEmpty()) {
    1162                 :           nsBoxFrame::InvalidateInternal(parentDamage, 0, 0, aForChild,
    1163               0 :                                          aFlags | INVALIDATE_NO_THEBES_LAYERS);
    1164                 :         }
    1165                 :       }
    1166                 :     } else {
    1167               0 :       if (!parentDamage.IsEmpty()) {
    1168               0 :         nsBoxFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags);
    1169                 :       }
    1170                 :     }
    1171                 :     return;
    1172                 :   }
    1173                 :   
    1174               0 :   nsBoxFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aFlags);
    1175                 : }
    1176                 : 
    1177                 : nscoord
    1178               0 : nsXULScrollFrame::GetBoxAscent(nsBoxLayoutState& aState)
    1179                 : {
    1180               0 :   if (!mInner.mScrolledFrame)
    1181               0 :     return 0;
    1182                 : 
    1183               0 :   nscoord ascent = mInner.mScrolledFrame->GetBoxAscent(aState);
    1184               0 :   nsMargin m(0,0,0,0);
    1185               0 :   GetBorderAndPadding(m);
    1186               0 :   ascent += m.top;
    1187               0 :   GetMargin(m);
    1188               0 :   ascent += m.top;
    1189                 : 
    1190               0 :   return ascent;
    1191                 : }
    1192                 : 
    1193                 : nsSize
    1194               0 : nsXULScrollFrame::GetPrefSize(nsBoxLayoutState& aState)
    1195                 : {
    1196                 : #ifdef DEBUG_LAYOUT
    1197                 :   PropagateDebug(aState);
    1198                 : #endif
    1199                 : 
    1200               0 :   nsSize pref = mInner.mScrolledFrame->GetPrefSize(aState);
    1201                 : 
    1202               0 :   nsGfxScrollFrameInner::ScrollbarStyles styles = GetScrollbarStyles();
    1203                 : 
    1204                 :   // scrolled frames don't have their own margins
    1205                 : 
    1206               0 :   if (mInner.mVScrollbarBox &&
    1207                 :       styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
    1208               0 :     nsSize vSize = mInner.mVScrollbarBox->GetPrefSize(aState);
    1209               0 :     nsBox::AddMargin(mInner.mVScrollbarBox, vSize);
    1210               0 :     pref.width += vSize.width;
    1211                 :   }
    1212                 :    
    1213               0 :   if (mInner.mHScrollbarBox &&
    1214                 :       styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
    1215               0 :     nsSize hSize = mInner.mHScrollbarBox->GetPrefSize(aState);
    1216               0 :     nsBox::AddMargin(mInner.mHScrollbarBox, hSize);
    1217               0 :     pref.height += hSize.height;
    1218                 :   }
    1219                 : 
    1220               0 :   AddBorderAndPadding(pref);
    1221                 :   bool widthSet, heightSet;
    1222               0 :   nsIBox::AddCSSPrefSize(this, pref, widthSet, heightSet);
    1223                 :   return pref;
    1224                 : }
    1225                 : 
    1226                 : nsSize
    1227               0 : nsXULScrollFrame::GetMinSize(nsBoxLayoutState& aState)
    1228                 : {
    1229                 : #ifdef DEBUG_LAYOUT
    1230                 :   PropagateDebug(aState);
    1231                 : #endif
    1232                 : 
    1233               0 :   nsSize min = mInner.mScrolledFrame->GetMinSizeForScrollArea(aState);
    1234                 : 
    1235               0 :   nsGfxScrollFrameInner::ScrollbarStyles styles = GetScrollbarStyles();
    1236                 :      
    1237               0 :   if (mInner.mVScrollbarBox &&
    1238                 :       styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
    1239               0 :      nsSize vSize = mInner.mVScrollbarBox->GetMinSize(aState);
    1240               0 :      AddMargin(mInner.mVScrollbarBox, vSize);
    1241               0 :      min.width += vSize.width;
    1242               0 :      if (min.height < vSize.height)
    1243               0 :         min.height = vSize.height;
    1244                 :   }
    1245                 :         
    1246               0 :   if (mInner.mHScrollbarBox &&
    1247                 :       styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
    1248               0 :      nsSize hSize = mInner.mHScrollbarBox->GetMinSize(aState);
    1249               0 :      AddMargin(mInner.mHScrollbarBox, hSize);
    1250               0 :      min.height += hSize.height;
    1251               0 :      if (min.width < hSize.width)
    1252               0 :         min.width = hSize.width;
    1253                 :   }
    1254                 : 
    1255               0 :   AddBorderAndPadding(min);
    1256                 :   bool widthSet, heightSet;
    1257               0 :   nsIBox::AddCSSMinSize(aState, this, min, widthSet, heightSet);
    1258                 :   return min;
    1259                 : }
    1260                 : 
    1261                 : nsSize
    1262               0 : nsXULScrollFrame::GetMaxSize(nsBoxLayoutState& aState)
    1263                 : {
    1264                 : #ifdef DEBUG_LAYOUT
    1265                 :   PropagateDebug(aState);
    1266                 : #endif
    1267                 : 
    1268               0 :   nsSize maxSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
    1269                 : 
    1270               0 :   AddBorderAndPadding(maxSize);
    1271                 :   bool widthSet, heightSet;
    1272               0 :   nsIBox::AddCSSMaxSize(this, maxSize, widthSet, heightSet);
    1273                 :   return maxSize;
    1274                 : }
    1275                 : 
    1276                 : #ifdef NS_DEBUG
    1277                 : NS_IMETHODIMP
    1278               0 : nsXULScrollFrame::GetFrameName(nsAString& aResult) const
    1279                 : {
    1280               0 :   return MakeFrameName(NS_LITERAL_STRING("XULScroll"), aResult);
    1281                 : }
    1282                 : #endif
    1283                 : 
    1284                 : NS_IMETHODIMP
    1285               0 : nsXULScrollFrame::DoLayout(nsBoxLayoutState& aState)
    1286                 : {
    1287               0 :   PRUint32 flags = aState.LayoutFlags();
    1288               0 :   nsresult rv = Layout(aState);
    1289               0 :   aState.SetLayoutFlags(flags);
    1290                 : 
    1291               0 :   nsBox::DoLayout(aState);
    1292               0 :   return rv;
    1293                 : }
    1294                 : 
    1295               0 : NS_QUERYFRAME_HEAD(nsXULScrollFrame)
    1296               0 :   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
    1297               0 :   NS_QUERYFRAME_ENTRY(nsIScrollableFrame)
    1298               0 :   NS_QUERYFRAME_ENTRY(nsIStatefulFrame)
    1299               0 : NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
    1300                 :  
    1301                 : //-------------------- Inner ----------------------
    1302                 : 
    1303                 : #define SMOOTH_SCROLL_PREF_NAME "general.smoothScroll"
    1304                 : 
    1305                 : const double kCurrentVelocityWeighting = 0.25;
    1306                 : const double kStopDecelerationWeighting = 0.4;
    1307                 : 
    1308                 : class nsGfxScrollFrameInner::AsyncScroll {
    1309                 : public:
    1310                 :   typedef mozilla::TimeStamp TimeStamp;
    1311                 :   typedef mozilla::TimeDuration TimeDuration;
    1312                 : 
    1313               0 :   AsyncScroll():
    1314               0 :     mIsFirstIteration(true)
    1315               0 :     {}
    1316                 : 
    1317               0 :   ~AsyncScroll() {
    1318               0 :     if (mScrollTimer) mScrollTimer->Cancel();
    1319               0 :   }
    1320                 : 
    1321                 :   nsPoint PositionAt(TimeStamp aTime);
    1322                 :   nsSize VelocityAt(TimeStamp aTime); // In nscoords per second
    1323                 : 
    1324                 :   void InitSmoothScroll(TimeStamp aTime, nsPoint aCurrentPos,
    1325                 :                         nsSize aCurrentVelocity, nsPoint aDestination,
    1326                 :                         nsIAtom *aOrigin);
    1327                 : 
    1328               0 :   bool IsFinished(TimeStamp aTime) {
    1329               0 :     return aTime > mStartTime + mDuration; // XXX or if we've hit the wall
    1330                 :   }
    1331                 : 
    1332                 :   nsCOMPtr<nsITimer> mScrollTimer;
    1333                 :   TimeStamp mStartTime;
    1334                 : 
    1335                 :   // mPrevStartTime holds previous 3 timestamps for intervals averaging (to
    1336                 :   // reduce duration fluctuations). When AsyncScroll is constructed and no
    1337                 :   // previous timestamps are available (indicated with mIsFirstIteration),
    1338                 :   // initialize mPrevStartTime using imaginary previous timestamps with maximum
    1339                 :   // relevant intervals between them.
    1340                 :   TimeStamp mPrevStartTime[3];
    1341                 :   bool mIsFirstIteration;
    1342                 : 
    1343                 :   // Cached Preferences values to avoid re-reading them when extending an existing
    1344                 :   // animation for the same event origin (can be as frequent as every 10(!)ms for 
    1345                 :   // a quick roll of the mouse wheel).
    1346                 :   // These values are minimum and maximum animation duration per event origin,
    1347                 :   // and a global ratio which defines how longer is the animation's duration
    1348                 :   // compared to the average recent events intervals (such that for a relatively
    1349                 :   // consistent events rate, the next event arrives before current animation ends)
    1350                 :   nsCOMPtr<nsIAtom> mOrigin;
    1351                 :   PRInt32 mOriginMinMS;
    1352                 :   PRInt32 mOriginMaxMS;
    1353                 :   double  mIntervalRatio;
    1354                 : 
    1355                 :   TimeDuration mDuration;
    1356                 :   nsPoint mStartPos;
    1357                 :   nsPoint mDestination;
    1358                 :   nsSMILKeySpline mTimingFunctionX;
    1359                 :   nsSMILKeySpline mTimingFunctionY;
    1360                 :   bool mIsSmoothScroll;
    1361                 : 
    1362                 : protected:
    1363               0 :   double ProgressAt(TimeStamp aTime) {
    1364               0 :     return clamped((aTime - mStartTime) / mDuration, 0.0, 1.0);
    1365                 :   }
    1366                 : 
    1367                 :   nscoord VelocityComponent(double aTimeProgress,
    1368                 :                             nsSMILKeySpline& aTimingFunction,
    1369                 :                             nscoord aStart, nscoord aDestination);
    1370                 : 
    1371                 :   // Initializes the timing function in such a way that the current velocity is
    1372                 :   // preserved.
    1373                 :   void InitTimingFunction(nsSMILKeySpline& aTimingFunction,
    1374                 :                           nscoord aCurrentPos, nscoord aCurrentVelocity,
    1375                 :                           nscoord aDestination);
    1376                 : 
    1377                 :   void InitDuration(nsIAtom *aOrigin);
    1378                 : };
    1379                 : 
    1380                 : nsPoint
    1381               0 : nsGfxScrollFrameInner::AsyncScroll::PositionAt(TimeStamp aTime) {
    1382               0 :   double progressX = mTimingFunctionX.GetSplineValue(ProgressAt(aTime));
    1383               0 :   double progressY = mTimingFunctionY.GetSplineValue(ProgressAt(aTime));
    1384                 :   return nsPoint((1 - progressX) * mStartPos.x + progressX * mDestination.x,
    1385               0 :                  (1 - progressY) * mStartPos.y + progressY * mDestination.y);
    1386                 : }
    1387                 : 
    1388                 : nsSize
    1389               0 : nsGfxScrollFrameInner::AsyncScroll::VelocityAt(TimeStamp aTime) {
    1390               0 :   double timeProgress = ProgressAt(aTime);
    1391                 :   return nsSize(VelocityComponent(timeProgress, mTimingFunctionX,
    1392                 :                                   mStartPos.x, mDestination.x),
    1393                 :                 VelocityComponent(timeProgress, mTimingFunctionY,
    1394               0 :                                   mStartPos.y, mDestination.y));
    1395                 : }
    1396                 : 
    1397                 : /*
    1398                 :  * Calculate/update mDuration, possibly dynamically according to events rate and event origin.
    1399                 :  * (also maintain previous timestamps - which are only used here).
    1400                 :  */
    1401                 : void
    1402               0 : nsGfxScrollFrameInner::AsyncScroll::InitDuration(nsIAtom *aOrigin) {
    1403               0 :   if (!aOrigin){
    1404               0 :     aOrigin = nsGkAtoms::other;
    1405                 :   }
    1406                 : 
    1407                 :   // Read preferences only on first iteration or for a different event origin.
    1408               0 :   if (mIsFirstIteration || aOrigin != mOrigin) {
    1409               0 :     mOrigin = aOrigin;
    1410               0 :     mOriginMinMS = mOriginMaxMS = 0;
    1411               0 :     bool isOriginSmoothnessEnabled = false;
    1412               0 :     mIntervalRatio = 1;
    1413                 : 
    1414                 :     // Default values for all preferences are defined in all.js
    1415                 :     static const PRInt32 kDefaultMinMS = 150, kDefaultMaxMS = 150;
    1416                 :     static const bool kDefaultIsSmoothEnabled = true;
    1417                 : 
    1418               0 :     nsCAutoString originName;
    1419               0 :     aOrigin->ToUTF8String(originName);
    1420               0 :     nsCAutoString prefBase = NS_LITERAL_CSTRING("general.smoothScroll.") + originName;
    1421                 : 
    1422               0 :     isOriginSmoothnessEnabled = Preferences::GetBool(prefBase.get(), kDefaultIsSmoothEnabled);
    1423               0 :     if (isOriginSmoothnessEnabled) {
    1424               0 :       nsCAutoString prefMin = prefBase + NS_LITERAL_CSTRING(".durationMinMS");
    1425               0 :       nsCAutoString prefMax = prefBase + NS_LITERAL_CSTRING(".durationMaxMS");
    1426               0 :       mOriginMinMS = Preferences::GetInt(prefMin.get(), kDefaultMinMS);
    1427               0 :       mOriginMaxMS = Preferences::GetInt(prefMax.get(), kDefaultMaxMS);
    1428                 : 
    1429                 :       static const PRInt32 kSmoothScrollMaxAllowedAnimationDurationMS = 10000;
    1430               0 :       mOriginMaxMS = clamped(mOriginMaxMS, 0, kSmoothScrollMaxAllowedAnimationDurationMS);
    1431               0 :       mOriginMinMS = clamped(mOriginMinMS, 0, mOriginMaxMS);
    1432                 :     }
    1433                 : 
    1434                 :     // Keep the animation duration longer than the average event intervals
    1435                 :     //   (to "connect" consecutive scroll animations before the scroll comes to a stop).
    1436                 :     static const double kDefaultDurationToIntervalRatio = 2; // Duplicated at all.js
    1437                 :     mIntervalRatio = Preferences::GetInt("general.smoothScroll.durationToIntervalRatio",
    1438               0 :                                          kDefaultDurationToIntervalRatio * 100) / 100.0;
    1439                 : 
    1440                 :     // Duration should be at least as long as the intervals -> ratio is at least 1
    1441               0 :     mIntervalRatio = NS_MAX(1.0, mIntervalRatio);
    1442                 : 
    1443               0 :     if (mIsFirstIteration) {
    1444                 :       // Starting a new scroll (i.e. not when extending an existing scroll animation),
    1445                 :       //   create imaginary prev timestamps with maximum relevant intervals between them.
    1446               0 :       mIsFirstIteration = false;
    1447                 : 
    1448                 :       // Longest relevant interval (which results in maximum duration)
    1449               0 :       TimeDuration maxDelta = TimeDuration::FromMilliseconds(mOriginMaxMS / mIntervalRatio);
    1450               0 :       mPrevStartTime[0] = mStartTime         - maxDelta;
    1451               0 :       mPrevStartTime[1] = mPrevStartTime[0]  - maxDelta;
    1452               0 :       mPrevStartTime[2] = mPrevStartTime[1]  - maxDelta;
    1453                 :     }
    1454                 :   }
    1455                 : 
    1456                 :   // Average last 3 delta durations (rounding errors up to 2ms are negligible for us)
    1457               0 :   PRInt32 eventsDeltaMs = (mStartTime - mPrevStartTime[2]).ToMilliseconds() / 3;
    1458               0 :   mPrevStartTime[2] = mPrevStartTime[1];
    1459               0 :   mPrevStartTime[1] = mPrevStartTime[0];
    1460               0 :   mPrevStartTime[0] = mStartTime;
    1461                 : 
    1462                 :   // Modulate duration according to events rate (quicker events -> shorter durations).
    1463                 :   // The desired effect is to use longer duration when scrolling slowly, such that
    1464                 :   // it's easier to follow, but reduce the duration to make it feel more snappy when
    1465                 :   // scrolling quickly. To reduce fluctuations of the duration, we average event
    1466                 :   // intervals using the recent 4 timestamps (now + three prev -> 3 intervals).
    1467               0 :   PRInt32 durationMS = clamped<PRInt32>(eventsDeltaMs * mIntervalRatio, mOriginMinMS, mOriginMaxMS);
    1468                 : 
    1469               0 :   mDuration = TimeDuration::FromMilliseconds(durationMS);
    1470               0 : }
    1471                 : 
    1472                 : void
    1473               0 : nsGfxScrollFrameInner::AsyncScroll::InitSmoothScroll(TimeStamp aTime,
    1474                 :                                                      nsPoint aCurrentPos,
    1475                 :                                                      nsSize aCurrentVelocity,
    1476                 :                                                      nsPoint aDestination,
    1477                 :                                                      nsIAtom *aOrigin) {
    1478               0 :   mStartTime = aTime;
    1479               0 :   mStartPos = aCurrentPos;
    1480               0 :   mDestination = aDestination;
    1481               0 :   InitDuration(aOrigin);
    1482               0 :   InitTimingFunction(mTimingFunctionX, mStartPos.x, aCurrentVelocity.width, aDestination.x);
    1483               0 :   InitTimingFunction(mTimingFunctionY, mStartPos.y, aCurrentVelocity.height, aDestination.y);
    1484               0 : }
    1485                 : 
    1486                 : 
    1487                 : nscoord
    1488               0 : nsGfxScrollFrameInner::AsyncScroll::VelocityComponent(double aTimeProgress,
    1489                 :                                                       nsSMILKeySpline& aTimingFunction,
    1490                 :                                                       nscoord aStart,
    1491                 :                                                       nscoord aDestination)
    1492                 : {
    1493                 :   double dt, dxy;
    1494               0 :   aTimingFunction.GetSplineDerivativeValues(aTimeProgress, dt, dxy);
    1495               0 :   if (dt == 0)
    1496               0 :     return dxy >= 0 ? nscoord_MAX : nscoord_MIN;
    1497                 : 
    1498               0 :   const TimeDuration oneSecond = TimeDuration::FromSeconds(1);
    1499               0 :   double slope = dxy / dt;
    1500               0 :   return (slope * (aDestination - aStart) / (mDuration / oneSecond));
    1501                 : }
    1502                 : 
    1503                 : void
    1504               0 : nsGfxScrollFrameInner::AsyncScroll::InitTimingFunction(nsSMILKeySpline& aTimingFunction,
    1505                 :                                                        nscoord aCurrentPos,
    1506                 :                                                        nscoord aCurrentVelocity,
    1507                 :                                                        nscoord aDestination)
    1508                 : {
    1509               0 :   if (aDestination == aCurrentPos || kCurrentVelocityWeighting == 0) {
    1510               0 :     aTimingFunction.Init(0, 0, 1 - kStopDecelerationWeighting, 1);
    1511               0 :     return;
    1512                 :   }
    1513                 : 
    1514               0 :   const TimeDuration oneSecond = TimeDuration::FromSeconds(1);
    1515               0 :   double slope = aCurrentVelocity * (mDuration / oneSecond) / (aDestination - aCurrentPos);
    1516               0 :   double normalization = sqrt(1.0 + slope * slope);
    1517               0 :   double dt = 1.0 / normalization * kCurrentVelocityWeighting;
    1518               0 :   double dxy = slope / normalization * kCurrentVelocityWeighting;
    1519               0 :   aTimingFunction.Init(dt, dxy, 1 - kStopDecelerationWeighting, 1);
    1520                 : }
    1521                 : 
    1522                 : static bool
    1523               0 : IsSmoothScrollingEnabled()
    1524                 : {
    1525               0 :   return Preferences::GetBool(SMOOTH_SCROLL_PREF_NAME, false);
    1526                 : }
    1527                 : 
    1528                 : class ScrollFrameActivityTracker : public nsExpirationTracker<nsGfxScrollFrameInner,4> {
    1529                 : public:
    1530                 :   // Wait for 3-4s between scrolls before we remove our layers.
    1531                 :   // That's 4 generations of 1s each.
    1532                 :   enum { TIMEOUT_MS = 1000 };
    1533               0 :   ScrollFrameActivityTracker()
    1534               0 :     : nsExpirationTracker<nsGfxScrollFrameInner,4>(TIMEOUT_MS) {}
    1535               0 :   ~ScrollFrameActivityTracker() {
    1536               0 :     AgeAllGenerations();
    1537               0 :   }
    1538                 : 
    1539               0 :   virtual void NotifyExpired(nsGfxScrollFrameInner *aObject) {
    1540               0 :     RemoveObject(aObject);
    1541               0 :     aObject->MarkInactive();
    1542               0 :   }
    1543                 : };
    1544                 : 
    1545                 : static ScrollFrameActivityTracker *gScrollFrameActivityTracker = nsnull;
    1546                 : 
    1547               0 : nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
    1548                 :                                              bool aIsRoot)
    1549                 :   : mHScrollbarBox(nsnull)
    1550                 :   , mVScrollbarBox(nsnull)
    1551                 :   , mScrolledFrame(nsnull)
    1552                 :   , mScrollCornerBox(nsnull)
    1553                 :   , mResizerBox(nsnull)
    1554                 :   , mOuter(aOuter)
    1555                 :   , mAsyncScroll(nsnull)
    1556                 :   , mDestination(0, 0)
    1557                 :   , mScrollPosAtLastPaint(0, 0)
    1558                 :   , mRestorePos(-1, -1)
    1559                 :   , mLastPos(-1, -1)
    1560                 :   , mNeverHasVerticalScrollbar(false)
    1561                 :   , mNeverHasHorizontalScrollbar(false)
    1562                 :   , mHasVerticalScrollbar(false)
    1563                 :   , mHasHorizontalScrollbar(false)
    1564                 :   , mFrameIsUpdatingScrollbar(false)
    1565                 :   , mDidHistoryRestore(false)
    1566                 :   , mIsRoot(aIsRoot)
    1567                 :   , mSupppressScrollbarUpdate(false)
    1568                 :   , mSkippedScrollbarLayout(false)
    1569                 :   , mHadNonInitialReflow(false)
    1570                 :   , mHorizontalOverflow(false)
    1571                 :   , mVerticalOverflow(false)
    1572                 :   , mPostedReflowCallback(false)
    1573                 :   , mMayHaveDirtyFixedChildren(false)
    1574                 :   , mUpdateScrollbarAttributes(false)
    1575                 :   , mCollapsedResizer(false)
    1576               0 :   , mShouldBuildLayer(false)
    1577                 : {
    1578               0 :   mScrollingActive = IsAlwaysActive();
    1579               0 : }
    1580                 : 
    1581               0 : nsGfxScrollFrameInner::~nsGfxScrollFrameInner()
    1582                 : {
    1583               0 :   if (mActivityExpirationState.IsTracked()) {
    1584               0 :     gScrollFrameActivityTracker->RemoveObject(this);
    1585                 :   }
    1586               0 :   if (gScrollFrameActivityTracker &&
    1587               0 :       gScrollFrameActivityTracker->IsEmpty()) {
    1588               0 :     delete gScrollFrameActivityTracker;
    1589               0 :     gScrollFrameActivityTracker = nsnull;
    1590                 :   }
    1591               0 :   delete mAsyncScroll;
    1592                 : 
    1593               0 :   if (mScrollActivityTimer) {
    1594               0 :     mScrollActivityTimer->Cancel();
    1595               0 :     mScrollActivityTimer = nsnull;
    1596                 :   }
    1597               0 : }
    1598                 : 
    1599                 : static nscoord
    1600               0 : Clamp(nscoord aLower, nscoord aVal, nscoord aUpper)
    1601                 : {
    1602               0 :   if (aVal < aLower)
    1603               0 :     return aLower;
    1604               0 :   if (aVal > aUpper)
    1605               0 :     return aUpper;
    1606               0 :   return aVal;
    1607                 : }
    1608                 : 
    1609                 : nsPoint
    1610               0 : nsGfxScrollFrameInner::ClampScrollPosition(const nsPoint& aPt) const
    1611                 : {
    1612               0 :   nsRect range = GetScrollRange();
    1613                 :   return nsPoint(Clamp(range.x, aPt.x, range.XMost()),
    1614               0 :                  Clamp(range.y, aPt.y, range.YMost()));
    1615                 : }
    1616                 : 
    1617                 : /*
    1618                 :  * Callback function from timer used in nsGfxScrollFrameInner::ScrollTo
    1619                 :  */
    1620                 : void
    1621               0 : nsGfxScrollFrameInner::AsyncScrollCallback(nsITimer *aTimer, void* anInstance)
    1622                 : {
    1623               0 :   nsGfxScrollFrameInner* self = static_cast<nsGfxScrollFrameInner*>(anInstance);
    1624               0 :   if (!self || !self->mAsyncScroll)
    1625               0 :     return;
    1626                 : 
    1627               0 :   if (self->mAsyncScroll->mIsSmoothScroll) {
    1628               0 :     TimeStamp now = TimeStamp::Now();
    1629               0 :     nsPoint destination = self->mAsyncScroll->PositionAt(now);
    1630               0 :     if (self->mAsyncScroll->IsFinished(now)) {
    1631               0 :       delete self->mAsyncScroll;
    1632               0 :       self->mAsyncScroll = nsnull;
    1633                 :     }
    1634                 : 
    1635               0 :     self->ScrollToImpl(destination);
    1636                 :   } else {
    1637               0 :     delete self->mAsyncScroll;
    1638               0 :     self->mAsyncScroll = nsnull;
    1639                 : 
    1640               0 :     self->ScrollToImpl(self->mDestination);
    1641                 :   }
    1642                 : }
    1643                 : 
    1644                 : /*
    1645                 :  * this method wraps calls to ScrollToImpl(), either in one shot or incrementally,
    1646                 :  *  based on the setting of the smoothness scroll pref
    1647                 :  */
    1648                 : void
    1649               0 : nsGfxScrollFrameInner::ScrollToWithOrigin(nsPoint aScrollPosition,
    1650                 :                                           nsIScrollableFrame::ScrollMode aMode,
    1651                 :                                           nsIAtom *aOrigin)
    1652                 : {
    1653               0 :   if (ShouldClampScrollPosition()) {
    1654               0 :     mDestination = ClampScrollPosition(aScrollPosition);
    1655                 :   } else {
    1656               0 :     mDestination = aScrollPosition;
    1657                 :   }
    1658                 : 
    1659               0 :   if (aMode == nsIScrollableFrame::INSTANT) {
    1660                 :     // Asynchronous scrolling is not allowed, so we'll kill any existing
    1661                 :     // async-scrolling process and do an instant scroll
    1662               0 :     delete mAsyncScroll;
    1663               0 :     mAsyncScroll = nsnull;
    1664               0 :     ScrollToImpl(mDestination);
    1665               0 :     return;
    1666                 :   }
    1667                 : 
    1668               0 :   TimeStamp now = TimeStamp::Now();
    1669               0 :   nsPoint currentPosition = GetScrollPosition();
    1670               0 :   nsSize currentVelocity(0, 0);
    1671                 :   bool isSmoothScroll = (aMode == nsIScrollableFrame::SMOOTH) &&
    1672               0 :                           IsSmoothScrollingEnabled();
    1673                 : 
    1674               0 :   if (mAsyncScroll) {
    1675               0 :     if (mAsyncScroll->mIsSmoothScroll) {
    1676               0 :       currentPosition = mAsyncScroll->PositionAt(now);
    1677               0 :       currentVelocity = mAsyncScroll->VelocityAt(now);
    1678                 :     }
    1679                 :   } else {
    1680               0 :     mAsyncScroll = new AsyncScroll;
    1681               0 :     mAsyncScroll->mScrollTimer = do_CreateInstance("@mozilla.org/timer;1");
    1682               0 :     if (!mAsyncScroll->mScrollTimer) {
    1683               0 :       delete mAsyncScroll;
    1684               0 :       mAsyncScroll = nsnull;
    1685                 :       // allocation failed. Scroll the normal way.
    1686               0 :       ScrollToImpl(mDestination);
    1687               0 :       return;
    1688                 :     }
    1689               0 :     if (isSmoothScroll) {
    1690               0 :       mAsyncScroll->mScrollTimer->InitWithFuncCallback(
    1691                 :         AsyncScrollCallback, this, 1000 / 60,
    1692               0 :         nsITimer::TYPE_REPEATING_SLACK);
    1693                 :     } else {
    1694               0 :       mAsyncScroll->mScrollTimer->InitWithFuncCallback(
    1695               0 :         AsyncScrollCallback, this, 0, nsITimer::TYPE_ONE_SHOT);
    1696                 :     }
    1697                 :   }
    1698                 : 
    1699               0 :   mAsyncScroll->mIsSmoothScroll = isSmoothScroll;
    1700                 : 
    1701               0 :   if (isSmoothScroll) {
    1702                 :     mAsyncScroll->InitSmoothScroll(now, currentPosition, currentVelocity,
    1703               0 :                                    mDestination, aOrigin);
    1704                 :   }
    1705                 : }
    1706                 : 
    1707                 : // We can't use nsContainerFrame::PositionChildViews here because
    1708                 : // we don't want to invalidate views that have moved.
    1709               0 : static void AdjustViews(nsIFrame* aFrame)
    1710                 : {
    1711               0 :   nsIView* view = aFrame->GetView();
    1712               0 :   if (view) {
    1713               0 :     nsPoint pt;
    1714               0 :     aFrame->GetParent()->GetClosestView(&pt);
    1715               0 :     pt += aFrame->GetPosition();
    1716               0 :     view->SetPosition(pt.x, pt.y);
    1717                 : 
    1718               0 :     return;
    1719                 :   }
    1720                 : 
    1721               0 :   if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
    1722               0 :     return;
    1723                 :   }
    1724                 : 
    1725                 :   // Call AdjustViews recursively for all child frames except the popup list as
    1726                 :   // the views for popups are not scrolled.
    1727               0 :   nsIFrame::ChildListIterator lists(aFrame);
    1728               0 :   for (; !lists.IsDone(); lists.Next()) {
    1729               0 :     if (lists.CurrentID() == nsIFrame::kPopupList) {
    1730               0 :       continue;
    1731                 :     }
    1732               0 :     nsFrameList::Enumerator childFrames(lists.CurrentList());
    1733               0 :     for (; !childFrames.AtEnd(); childFrames.Next()) {
    1734               0 :       AdjustViews(childFrames.get());
    1735                 :     }
    1736                 :   }
    1737                 : }
    1738                 : 
    1739                 : static bool
    1740               0 : CanScrollWithBlitting(nsIFrame* aFrame)
    1741                 : {
    1742               0 :   if (aFrame->GetStateBits() & NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL)
    1743               0 :     return false;
    1744                 : 
    1745               0 :   for (nsIFrame* f = aFrame; f;
    1746                 :        f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
    1747               0 :     if (nsSVGIntegrationUtils::UsingEffectsForFrame(f) ||
    1748               0 :         f->IsFrameOfType(nsIFrame::eSVG)) {
    1749               0 :       return false;
    1750                 :     }
    1751               0 :     nsIScrollableFrame* sf = do_QueryFrame(f);
    1752               0 :     if ((sf || f->IsFrameOfType(nsIFrame::eReplaced)) &&
    1753               0 :         nsLayoutUtils::HasNonZeroCorner(f->GetStyleBorder()->mBorderRadius))
    1754               0 :       return false;
    1755               0 :     if (nsLayoutUtils::IsPopup(f))
    1756               0 :       break;
    1757                 :   }
    1758               0 :   return true;
    1759                 : }
    1760                 : 
    1761                 : static void
    1762               0 : InvalidateFixedBackgroundFramesFromList(nsDisplayListBuilder* aBuilder,
    1763                 :                                         nsIFrame* aMovingFrame,
    1764                 :                                         const nsDisplayList& aList)
    1765                 : {
    1766               0 :   for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
    1767               0 :     nsDisplayList* sublist = item->GetList();
    1768               0 :     if (sublist) {
    1769               0 :       InvalidateFixedBackgroundFramesFromList(aBuilder, aMovingFrame, *sublist);
    1770               0 :       continue;
    1771                 :     }
    1772               0 :     nsIFrame* f = item->GetUnderlyingFrame();
    1773               0 :     if (f &&
    1774               0 :         item->IsVaryingRelativeToMovingFrame(aBuilder, aMovingFrame)) {
    1775               0 :       if (FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(aBuilder, item)) {
    1776                 :         // FrameLayerBuilder does not take care of scrolling this one
    1777               0 :         f->Invalidate(item->GetVisibleRect() - item->ToReferenceFrame());
    1778                 :       }
    1779                 :     }
    1780                 :   }
    1781               0 : }
    1782                 : 
    1783                 : static void
    1784               0 : InvalidateFixedBackgroundFrames(nsIFrame* aRootFrame,
    1785                 :                                 nsIFrame* aMovingFrame,
    1786                 :                                 const nsRect& aUpdateRect)
    1787                 : {
    1788               0 :   if (!aMovingFrame->PresContext()->MayHaveFixedBackgroundFrames())
    1789               0 :     return;
    1790                 : 
    1791               0 :   NS_ASSERTION(aRootFrame != aMovingFrame,
    1792                 :                "The root frame shouldn't be the one that's moving, that makes no sense");
    1793                 : 
    1794                 :   // Build the 'after' display list over the whole area of interest.
    1795               0 :   nsDisplayListBuilder builder(aRootFrame, nsDisplayListBuilder::OTHER, true);
    1796               0 :   builder.EnterPresShell(aRootFrame, aUpdateRect);
    1797               0 :   nsDisplayList list;
    1798                 :   nsresult rv =
    1799               0 :     aRootFrame->BuildDisplayListForStackingContext(&builder, aUpdateRect, &list);
    1800               0 :   builder.LeavePresShell(aRootFrame, aUpdateRect);
    1801               0 :   if (NS_FAILED(rv))
    1802                 :     return;
    1803                 : 
    1804               0 :   nsRegion visibleRegion(aUpdateRect);
    1805               0 :   list.ComputeVisibilityForRoot(&builder, &visibleRegion);
    1806                 : 
    1807               0 :   InvalidateFixedBackgroundFramesFromList(&builder, aMovingFrame, list);
    1808               0 :   list.DeleteAll();
    1809                 : }
    1810                 : 
    1811               0 : bool nsGfxScrollFrameInner::IsIgnoringViewportClipping() const
    1812                 : {
    1813               0 :   if (!mIsRoot)
    1814               0 :     return false;
    1815                 :   nsSubDocumentFrame* subdocFrame = static_cast<nsSubDocumentFrame*>
    1816               0 :     (nsLayoutUtils::GetCrossDocParentFrame(mOuter->PresContext()->PresShell()->GetRootFrame()));
    1817               0 :   return subdocFrame && !subdocFrame->ShouldClipSubdocument();
    1818                 : }
    1819                 : 
    1820               0 : bool nsGfxScrollFrameInner::ShouldClampScrollPosition() const
    1821                 : {
    1822               0 :   if (!mIsRoot)
    1823               0 :     return true;
    1824                 :   nsSubDocumentFrame* subdocFrame = static_cast<nsSubDocumentFrame*>
    1825               0 :     (nsLayoutUtils::GetCrossDocParentFrame(mOuter->PresContext()->PresShell()->GetRootFrame()));
    1826               0 :   return !subdocFrame || subdocFrame->ShouldClampScrollPosition();
    1827                 : }
    1828                 : 
    1829               0 : bool nsGfxScrollFrameInner::IsAlwaysActive() const
    1830                 : {
    1831                 :   // The root scrollframe for a non-chrome document which is the direct
    1832                 :   // child of a chrome document is always treated as "active".
    1833                 :   // XXX maybe we should extend this so that IFRAMEs which are fill the
    1834                 :   // entire viewport (like GMail!) are always active
    1835               0 :   return mIsRoot && mOuter->PresContext()->IsRootContentDocument();
    1836                 : }
    1837                 : 
    1838               0 : void nsGfxScrollFrameInner::MarkInactive()
    1839                 : {
    1840               0 :   if (IsAlwaysActive() || !mScrollingActive)
    1841               0 :     return;
    1842                 : 
    1843               0 :   mScrollingActive = false;
    1844               0 :   mOuter->InvalidateFrameSubtree();
    1845                 : }
    1846                 : 
    1847               0 : void nsGfxScrollFrameInner::MarkActive()
    1848                 : {
    1849               0 :   if (IsAlwaysActive())
    1850               0 :     return;
    1851                 : 
    1852               0 :   mScrollingActive = true;
    1853               0 :   if (mActivityExpirationState.IsTracked()) {
    1854               0 :     gScrollFrameActivityTracker->MarkUsed(this);
    1855                 :   } else {
    1856               0 :     if (!gScrollFrameActivityTracker) {
    1857               0 :       gScrollFrameActivityTracker = new ScrollFrameActivityTracker();
    1858                 :     }
    1859               0 :     gScrollFrameActivityTracker->AddObject(this);
    1860                 :   }
    1861                 : }
    1862                 : 
    1863               0 : void nsGfxScrollFrameInner::ScrollVisual(nsPoint aOldScrolledFramePos)
    1864                 : {
    1865               0 :   nsRootPresContext* rootPresContext = mOuter->PresContext()->GetRootPresContext();
    1866               0 :   if (!rootPresContext) {
    1867               0 :     return;
    1868                 :   }
    1869                 : 
    1870               0 :   rootPresContext->RequestUpdatePluginGeometry(mOuter);
    1871                 : 
    1872               0 :   AdjustViews(mScrolledFrame);
    1873                 :   // We need to call this after fixing up the view positions
    1874                 :   // to be consistent with the frame hierarchy.
    1875               0 :   PRUint32 flags = nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT;
    1876               0 :   bool canScrollWithBlitting = CanScrollWithBlitting(mOuter);
    1877               0 :   mOuter->RemoveStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL);
    1878               0 :   if (IsScrollingActive()) {
    1879               0 :     if (!canScrollWithBlitting) {
    1880               0 :       MarkInactive();
    1881                 :     } else {
    1882               0 :       flags |= nsIFrame::INVALIDATE_NO_THEBES_LAYERS;
    1883                 :     }
    1884                 :   }
    1885               0 :   if (canScrollWithBlitting) {
    1886               0 :     MarkActive();
    1887                 :   }
    1888                 : 
    1889               0 :   nsRect invalidateRect, displayport;
    1890               0 :   if (IsIgnoringViewportClipping()) {
    1891               0 :     nsRect visualOverflow = mScrolledFrame->GetVisualOverflowRect();
    1892               0 :     invalidateRect.UnionRect(visualOverflow + mScrolledFrame->GetPosition(),
    1893               0 :             visualOverflow + aOldScrolledFramePos);
    1894                 :   } else {
    1895                 :     invalidateRect =
    1896               0 :       (nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayport)) ?
    1897               0 :       displayport : mScrollPort;
    1898                 :   }
    1899                 : 
    1900               0 :   mOuter->InvalidateWithFlags(invalidateRect, flags);
    1901                 : 
    1902               0 :   if (flags & nsIFrame::INVALIDATE_NO_THEBES_LAYERS) {
    1903               0 :     nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(mOuter);
    1904                 :     nsRect update =
    1905               0 :       GetScrollPortRect() + mOuter->GetOffsetToCrossDoc(displayRoot);
    1906                 :     update = update.ConvertAppUnitsRoundOut(
    1907               0 :       mOuter->PresContext()->AppUnitsPerDevPixel(),
    1908               0 :       displayRoot->PresContext()->AppUnitsPerDevPixel());
    1909               0 :     InvalidateFixedBackgroundFrames(displayRoot, mScrolledFrame, update);
    1910                 :   }
    1911                 : }
    1912                 : 
    1913                 : static PRInt32
    1914               0 : ClampInt(nscoord aLower, nscoord aVal, nscoord aUpper, nscoord aAppUnitsPerPixel)
    1915                 : {
    1916               0 :   PRInt32 low = NSToIntCeil(float(aLower)/aAppUnitsPerPixel);
    1917               0 :   PRInt32 high = NSToIntFloor(float(aUpper)/aAppUnitsPerPixel);
    1918               0 :   PRInt32 v = NSToIntRound(float(aVal)/aAppUnitsPerPixel);
    1919               0 :   NS_ASSERTION(low <= high, "No integers in range; 0 is supposed to be in range");
    1920               0 :   if (v < low)
    1921               0 :     return low;
    1922               0 :   if (v > high)
    1923               0 :     return high;
    1924               0 :   return v;
    1925                 : }
    1926                 : 
    1927                 : nsPoint
    1928               0 : nsGfxScrollFrameInner::RestrictToDevPixels(const nsPoint& aPt,
    1929                 :                                            nsIntPoint* aPtDevPx,
    1930                 :                                            bool aShouldClamp) const
    1931                 : {
    1932               0 :   nsPresContext* presContext = mOuter->PresContext();
    1933               0 :   nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
    1934                 :   // Convert to device pixels so we scroll to an integer offset of device
    1935                 :   // pixels. But we also need to make sure that our position remains
    1936                 :   // inside the allowed region.
    1937               0 :   if (aShouldClamp) {
    1938               0 :     nsRect scrollRange = GetScrollRange();
    1939                 :     *aPtDevPx = nsIntPoint(ClampInt(scrollRange.x, aPt.x, scrollRange.XMost(), appUnitsPerDevPixel),
    1940               0 :                            ClampInt(scrollRange.y, aPt.y, scrollRange.YMost(), appUnitsPerDevPixel));
    1941                 :   } else {
    1942                 :     *aPtDevPx = nsIntPoint(NSAppUnitsToIntPixels(aPt.x, appUnitsPerDevPixel),
    1943               0 :                            NSAppUnitsToIntPixels(aPt.y, appUnitsPerDevPixel));
    1944                 :   }
    1945                 :   return nsPoint(NSIntPixelsToAppUnits(aPtDevPx->x, appUnitsPerDevPixel),
    1946               0 :                  NSIntPixelsToAppUnits(aPtDevPx->y, appUnitsPerDevPixel));
    1947                 : }
    1948                 : 
    1949                 : /* static */ void
    1950               0 : nsGfxScrollFrameInner::ScrollActivityCallback(nsITimer *aTimer, void* anInstance)
    1951                 : {
    1952               0 :   nsGfxScrollFrameInner* self = static_cast<nsGfxScrollFrameInner*>(anInstance);
    1953                 : 
    1954                 :   // Fire the synth mouse move.
    1955               0 :   self->mScrollActivityTimer->Cancel();
    1956               0 :   self->mScrollActivityTimer = nsnull;
    1957               0 :   self->mOuter->PresContext()->PresShell()->SynthesizeMouseMove(true);
    1958               0 : }
    1959                 : 
    1960                 : 
    1961                 : void
    1962               0 : nsGfxScrollFrameInner::ScheduleSyntheticMouseMove()
    1963                 : {
    1964               0 :   if (!mScrollActivityTimer) {
    1965               0 :     mScrollActivityTimer = do_CreateInstance("@mozilla.org/timer;1");
    1966               0 :     if (!mScrollActivityTimer)
    1967               0 :       return;
    1968                 :   }
    1969                 : 
    1970               0 :   mScrollActivityTimer->InitWithFuncCallback(
    1971               0 :         ScrollActivityCallback, this, 100, nsITimer::TYPE_ONE_SHOT);
    1972                 : }
    1973                 : 
    1974                 : void
    1975               0 : nsGfxScrollFrameInner::ScrollToImpl(nsPoint aPt)
    1976                 : {
    1977               0 :   nsPresContext* presContext = mOuter->PresContext();
    1978               0 :   nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
    1979               0 :   nsIntPoint ptDevPx;
    1980                 : 
    1981               0 :   nsPoint pt = RestrictToDevPixels(aPt, &ptDevPx, ShouldClampScrollPosition());
    1982                 : 
    1983               0 :   nsPoint curPos = GetScrollPosition();
    1984               0 :   if (pt == curPos) {
    1985               0 :     return;
    1986                 :   }
    1987                 :   nsIntPoint curPosDevPx(NSAppUnitsToIntPixels(curPos.x, appUnitsPerDevPixel),
    1988               0 :                          NSAppUnitsToIntPixels(curPos.y, appUnitsPerDevPixel));
    1989                 :   // We maintain the invariant that the scroll position is a multiple of device
    1990                 :   // pixels.
    1991               0 :   NS_ASSERTION(curPosDevPx.x*appUnitsPerDevPixel == curPos.x,
    1992                 :                "curPos.x not a multiple of device pixels");
    1993               0 :   NS_ASSERTION(curPosDevPx.y*appUnitsPerDevPixel == curPos.y,
    1994                 :                "curPos.y not a multiple of device pixels");
    1995                 : 
    1996                 :   // notify the listeners.
    1997               0 :   for (PRUint32 i = 0; i < mListeners.Length(); i++) {
    1998               0 :     mListeners[i]->ScrollPositionWillChange(pt.x, pt.y);
    1999                 :   }
    2000                 : 
    2001               0 :   nsPoint oldScrollFramePos = mScrolledFrame->GetPosition();
    2002                 :   // Update frame position for scrolling
    2003               0 :   mScrolledFrame->SetPosition(mScrollPort.TopLeft() - pt);
    2004                 : 
    2005                 :   // We pass in the amount to move visually
    2006               0 :   ScrollVisual(oldScrollFramePos);
    2007                 : 
    2008               0 :   ScheduleSyntheticMouseMove();
    2009               0 :   UpdateScrollbarPosition();
    2010               0 :   PostScrollEvent();
    2011                 : 
    2012                 :   // notify the listeners.
    2013               0 :   for (PRUint32 i = 0; i < mListeners.Length(); i++) {
    2014               0 :     mListeners[i]->ScrollPositionDidChange(pt.x, pt.y);
    2015                 :   }
    2016                 : }
    2017                 : 
    2018                 : static void
    2019               0 : AppendToTop(nsDisplayListBuilder* aBuilder, nsDisplayList* aDest,
    2020                 :             nsDisplayList* aSource, nsIFrame* aSourceFrame, bool aOwnLayer)
    2021                 : {
    2022               0 :   if (aSource->IsEmpty())
    2023               0 :     return;
    2024               0 :   if (aOwnLayer) {
    2025                 :     aDest->AppendNewToTop(
    2026               0 :         new (aBuilder) nsDisplayOwnLayer(aBuilder, aSourceFrame, aSource));
    2027                 :   } else {
    2028               0 :     aDest->AppendToTop(aSource);
    2029                 :   }  
    2030                 : }
    2031                 : 
    2032                 : void
    2033               0 : nsGfxScrollFrameInner::AppendScrollPartsTo(nsDisplayListBuilder*   aBuilder,
    2034                 :                                            const nsRect&           aDirtyRect,
    2035                 :                                            const nsDisplayListSet& aLists,
    2036                 :                                            bool&                   aCreateLayer,
    2037                 :                                            bool                    aPositioned)
    2038                 : {
    2039               0 :   for (nsIFrame* kid = mOuter->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
    2040               0 :     if (kid == mScrolledFrame ||
    2041               0 :         (kid->GetStyleDisplay()->IsPositioned() != aPositioned))
    2042               0 :       continue;
    2043                 : 
    2044               0 :     nsDisplayListCollection partList;
    2045                 :     mOuter->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, partList,
    2046               0 :                                      nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
    2047                 : 
    2048                 :     // Don't append textarea resizers to the positioned descendants because
    2049                 :     // we don't want them to float on top of overlapping elements.
    2050               0 :     bool appendToPositioned = aPositioned && !(kid == mResizerBox && !mIsRoot);
    2051                 : 
    2052                 :     nsDisplayList* dest = appendToPositioned ?
    2053               0 :       aLists.PositionedDescendants() : aLists.BorderBackground();
    2054                 : 
    2055                 :     // DISPLAY_CHILD_FORCE_STACKING_CONTEXT put everything into
    2056                 :     // partList.PositionedDescendants().
    2057                 :     ::AppendToTop(aBuilder, dest,
    2058                 :                   partList.PositionedDescendants(), kid,
    2059               0 :                   aCreateLayer);
    2060                 :   }
    2061               0 : }
    2062                 : 
    2063                 : bool
    2064               0 : nsGfxScrollFrameInner::ShouldBuildLayer() const
    2065                 : {
    2066               0 :   return mShouldBuildLayer;
    2067                 : }
    2068                 : 
    2069                 : class ScrollLayerWrapper : public nsDisplayWrapper
    2070                 : {
    2071                 : public:
    2072               0 :   ScrollLayerWrapper(nsIFrame* aScrollFrame, nsIFrame* aScrolledFrame)
    2073                 :     : mCount(0)
    2074                 :     , mProps(aScrolledFrame->Properties())
    2075                 :     , mScrollFrame(aScrollFrame)
    2076               0 :     , mScrolledFrame(aScrolledFrame)
    2077                 :   {
    2078               0 :     SetCount(0);
    2079               0 :   }
    2080                 : 
    2081               0 :   virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
    2082                 :                                   nsIFrame* aFrame,
    2083                 :                                   nsDisplayList* aList) {
    2084               0 :     SetCount(++mCount);
    2085               0 :     return new (aBuilder) nsDisplayScrollLayer(aBuilder, aList, mScrolledFrame, mScrolledFrame, mScrollFrame);
    2086                 :   }
    2087                 : 
    2088               0 :   virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
    2089                 :                                   nsDisplayItem* aItem) {
    2090                 : 
    2091               0 :     SetCount(++mCount);
    2092               0 :     return new (aBuilder) nsDisplayScrollLayer(aBuilder, aItem, aItem->GetUnderlyingFrame(), mScrolledFrame, mScrollFrame);
    2093                 :   }
    2094                 : 
    2095                 : protected:
    2096               0 :   void SetCount(PRWord aCount) {
    2097               0 :     mProps.Set(nsIFrame::ScrollLayerCount(), reinterpret_cast<void*>(aCount));
    2098               0 :   }
    2099                 : 
    2100                 :   PRWord mCount;
    2101                 :   FrameProperties mProps;
    2102                 :   nsIFrame* mScrollFrame;
    2103                 :   nsIFrame* mScrolledFrame;
    2104                 : };
    2105                 : 
    2106                 : nsresult
    2107               0 : nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    2108                 :                                         const nsRect&           aDirtyRect,
    2109                 :                                         const nsDisplayListSet& aLists)
    2110                 : {
    2111               0 :   nsresult rv = mOuter->DisplayBorderBackgroundOutline(aBuilder, aLists);
    2112               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2113                 : 
    2114               0 :   if (aBuilder->IsPaintingToWindow()) {
    2115               0 :     mScrollPosAtLastPaint = GetScrollPosition();
    2116               0 :     if (IsScrollingActive() && !CanScrollWithBlitting(mOuter)) {
    2117               0 :       MarkInactive();
    2118                 :     }
    2119                 :   }
    2120                 : 
    2121               0 :   if (aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping()) {
    2122                 :     // Don't clip the scrolled child, and don't paint scrollbars/scrollcorner.
    2123                 :     // The scrolled frame shouldn't have its own background/border, so we
    2124                 :     // can just pass aLists directly.
    2125                 :     return mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame,
    2126               0 :                                             aDirtyRect, aLists);
    2127                 :   }
    2128                 : 
    2129                 :   // We put scrollbars in their own layers when this is the root scroll
    2130                 :   // frame and we are a toplevel content document. In this situation, the
    2131                 :   // scrollbar(s) would normally be assigned their own layer anyway, since
    2132                 :   // they're not scrolled with the rest of the document. But when both
    2133                 :   // scrollbars are visible, the layer's visible rectangle would be the size
    2134                 :   // of the viewport, so most layer implementations would create a layer buffer
    2135                 :   // that's much larger than necessary. Creating independent layers for each
    2136                 :   // scrollbar works around the problem.
    2137                 :   bool createLayersForScrollbars = mIsRoot &&
    2138               0 :     mOuter->PresContext()->IsRootContentDocument();
    2139                 : 
    2140                 :   // Now display the scrollbars and scrollcorner. These parts are drawn
    2141                 :   // in the border-background layer, on top of our own background and
    2142                 :   // borders and underneath borders and backgrounds of later elements
    2143                 :   // in the tree.
    2144                 :   // Note that this does not apply for overlay scrollbars; those are drawn
    2145                 :   // in the positioned-elements layer on top of everything else by the call
    2146                 :   // to AppendScrollPartsTo(..., true) further down.
    2147                 :   AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, createLayersForScrollbars,
    2148               0 :                       false);
    2149                 : 
    2150                 :   // Overflow clipping can never clip frames outside our subtree, so there
    2151                 :   // is no need to worry about whether we are a moving frame that might clip
    2152                 :   // non-moving frames.
    2153               0 :   nsRect dirtyRect;
    2154                 :   // Not all our descendants will be clipped by overflow clipping, but all
    2155                 :   // the ones that aren't clipped will be out of flow frames that have already
    2156                 :   // had dirty rects saved for them by their parent frames calling
    2157                 :   // MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our
    2158                 :   // dirty rect here.
    2159               0 :   dirtyRect.IntersectRect(aDirtyRect, mScrollPort);
    2160                 : 
    2161                 :   // Override the dirty rectangle if the displayport has been set.
    2162                 :   bool usingDisplayport =
    2163               0 :     nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &dirtyRect);
    2164                 : 
    2165               0 :   nsDisplayListCollection set;
    2166               0 :   rv = mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, set);
    2167               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2168                 : 
    2169                 :   // Since making new layers is expensive, only use nsDisplayScrollLayer
    2170                 :   // if the area is scrollable.
    2171               0 :   nsRect scrollRange = GetScrollRange();
    2172               0 :   ScrollbarStyles styles = GetScrollbarStylesFromFrame();
    2173                 :   mShouldBuildLayer =
    2174               0 :      (XRE_GetProcessType() == GeckoProcessType_Content &&
    2175                 :      (styles.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN ||
    2176                 :       styles.mVertical != NS_STYLE_OVERFLOW_HIDDEN) &&
    2177                 :      (scrollRange.width > 0 ||
    2178                 :       scrollRange.height > 0) &&
    2179               0 :      (!mIsRoot || !mOuter->PresContext()->IsRootContentDocument()));
    2180                 : 
    2181               0 :   if (ShouldBuildLayer()) {
    2182                 :     // ScrollLayerWrapper must always be created because it initializes the
    2183                 :     // scroll layer count. The display lists depend on this.
    2184               0 :     ScrollLayerWrapper wrapper(mOuter, mScrolledFrame);
    2185                 : 
    2186               0 :     if (usingDisplayport) {
    2187                 :       // Once a displayport is set, assume that scrolling needs to be fast
    2188                 :       // so create a layer with all the content inside. The compositor
    2189                 :       // process will be able to scroll the content asynchronously.
    2190               0 :       wrapper.WrapListsInPlace(aBuilder, mOuter, set);
    2191                 :     }
    2192                 : 
    2193                 :     // In case we are not using displayport or the nsDisplayScrollLayers are
    2194                 :     // flattened during visibility computation, we still need to export the
    2195                 :     // metadata about this scroll box to the compositor process.
    2196                 :     nsDisplayScrollInfoLayer* layerItem = new (aBuilder) nsDisplayScrollInfoLayer(
    2197               0 :       aBuilder, mScrolledFrame, mOuter);
    2198               0 :     set.BorderBackground()->AppendNewToBottom(layerItem);
    2199                 :   }
    2200                 : 
    2201               0 :   nsRect clip;
    2202               0 :   clip = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
    2203                 : 
    2204                 :   nscoord radii[8];
    2205                 :   // Our override of GetBorderRadii ensures we never have a radius at
    2206                 :   // the corners where we have a scrollbar.
    2207               0 :   mOuter->GetPaddingBoxBorderRadii(radii);
    2208                 : 
    2209                 :   // mScrolledFrame may have given us a background, e.g., the scrolled canvas
    2210                 :   // frame below the viewport. If so, we want it to be clipped. We also want
    2211                 :   // to end up on our BorderBackground list.
    2212                 :   // If we are the viewport scrollframe, then clip all our descendants (to ensure
    2213                 :   // that fixed-pos elements get clipped by us).
    2214                 :   rv = mOuter->OverflowClip(aBuilder, set, aLists, clip, radii,
    2215               0 :                             true, mIsRoot);
    2216               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2217                 : 
    2218                 :   // Now display overlay scrollbars and the resizer, if we have one.
    2219                 :   AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, createLayersForScrollbars,
    2220               0 :                       true);
    2221                 : 
    2222               0 :   return NS_OK;
    2223                 : }
    2224                 : 
    2225               0 : static void HandleScrollPref(nsIScrollable *aScrollable, PRInt32 aOrientation,
    2226                 :                              PRUint8& aValue)
    2227                 : {
    2228                 :   PRInt32 pref;
    2229               0 :   aScrollable->GetDefaultScrollbarPreferences(aOrientation, &pref);
    2230               0 :   switch (pref) {
    2231                 :     case nsIScrollable::Scrollbar_Auto:
    2232                 :       // leave |aValue| untouched
    2233               0 :       break;
    2234                 :     case nsIScrollable::Scrollbar_Never:
    2235               0 :       aValue = NS_STYLE_OVERFLOW_HIDDEN;
    2236               0 :       break;
    2237                 :     case nsIScrollable::Scrollbar_Always:
    2238               0 :       aValue = NS_STYLE_OVERFLOW_SCROLL;
    2239               0 :       break;
    2240                 :   }
    2241               0 : }
    2242                 : 
    2243                 : nsGfxScrollFrameInner::ScrollbarStyles
    2244               0 : nsGfxScrollFrameInner::GetScrollbarStylesFromFrame() const
    2245                 : {
    2246               0 :   ScrollbarStyles result;
    2247                 : 
    2248               0 :   nsPresContext* presContext = mOuter->PresContext();
    2249               0 :   if (!presContext->IsDynamic() &&
    2250               0 :       !(mIsRoot && presContext->HasPaginatedScrolling())) {
    2251               0 :     return ScrollbarStyles(NS_STYLE_OVERFLOW_HIDDEN, NS_STYLE_OVERFLOW_HIDDEN);
    2252                 :   }
    2253                 : 
    2254               0 :   if (mIsRoot) {
    2255               0 :     result = presContext->GetViewportOverflowOverride();
    2256                 : 
    2257               0 :     nsCOMPtr<nsISupports> container = presContext->GetContainer();
    2258               0 :     nsCOMPtr<nsIScrollable> scrollable = do_QueryInterface(container);
    2259               0 :     if (scrollable) {
    2260                 :       HandleScrollPref(scrollable, nsIScrollable::ScrollOrientation_X,
    2261               0 :                        result.mHorizontal);
    2262                 :       HandleScrollPref(scrollable, nsIScrollable::ScrollOrientation_Y,
    2263               0 :                        result.mVertical);
    2264                 :       // XXX EVIL COMPILER BUG BE CAREFUL WHEN CHANGING
    2265                 :       //     There is a bug in the Android compiler :(
    2266                 :       //     It seems that the compiler optimizes something out and uses
    2267                 :       //     a bad value for result if we don't directly return here.
    2268               0 :       return result;
    2269                 :     }
    2270                 :   } else {
    2271               0 :     const nsStyleDisplay *disp = mOuter->GetStyleDisplay();
    2272               0 :     result.mHorizontal = disp->mOverflowX;
    2273               0 :     result.mVertical = disp->mOverflowY;
    2274                 :   }
    2275                 : 
    2276               0 :   return result;
    2277                 : }
    2278                 : 
    2279                 : static nscoord
    2280               0 : AlignToDevPixelRoundingToZero(nscoord aVal, PRInt32 aAppUnitsPerDevPixel)
    2281                 : {
    2282               0 :   return (aVal/aAppUnitsPerDevPixel)*aAppUnitsPerDevPixel;
    2283                 : }
    2284                 : 
    2285                 : nsRect
    2286               0 : nsGfxScrollFrameInner::GetScrollRange() const
    2287                 : {
    2288               0 :   nsRect range = GetScrolledRect();
    2289               0 :   range.width -= mScrollPort.width;
    2290               0 :   range.height -= mScrollPort.height;
    2291                 : 
    2292               0 :   nsPresContext* presContext = mOuter->PresContext();
    2293               0 :   PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
    2294                 :   range.width =
    2295               0 :     AlignToDevPixelRoundingToZero(range.XMost(), appUnitsPerDevPixel) - range.x;
    2296                 :   range.height =
    2297               0 :     AlignToDevPixelRoundingToZero(range.YMost(), appUnitsPerDevPixel) - range.y;
    2298               0 :   range.x = AlignToDevPixelRoundingToZero(range.x, appUnitsPerDevPixel);
    2299               0 :   range.y = AlignToDevPixelRoundingToZero(range.y, appUnitsPerDevPixel);
    2300                 :   return range;
    2301                 : }
    2302                 : 
    2303                 : static void
    2304               0 : AdjustForWholeDelta(PRInt32 aDelta, nscoord* aCoord)
    2305                 : {
    2306               0 :   if (aDelta < 0) {
    2307               0 :     *aCoord = nscoord_MIN;
    2308               0 :   } else if (aDelta > 0) {
    2309               0 :     *aCoord = nscoord_MAX;
    2310                 :   }
    2311               0 : }
    2312                 : 
    2313                 : void
    2314               0 : nsGfxScrollFrameInner::ScrollBy(nsIntPoint aDelta,
    2315                 :                                 nsIScrollableFrame::ScrollUnit aUnit,
    2316                 :                                 nsIScrollableFrame::ScrollMode aMode,
    2317                 :                                 nsIntPoint* aOverflow,
    2318                 :                                 nsIAtom *aOrigin)
    2319                 : {
    2320               0 :   nsSize deltaMultiplier;
    2321               0 :   if (!aOrigin){
    2322               0 :     aOrigin = nsGkAtoms::other;
    2323                 :   }
    2324               0 :   bool isGenericOrigin = (aOrigin == nsGkAtoms::other);
    2325               0 :   switch (aUnit) {
    2326                 :   case nsIScrollableFrame::DEVICE_PIXELS: {
    2327                 :     nscoord appUnitsPerDevPixel =
    2328               0 :       mOuter->PresContext()->AppUnitsPerDevPixel();
    2329               0 :     deltaMultiplier = nsSize(appUnitsPerDevPixel, appUnitsPerDevPixel);
    2330               0 :     if (isGenericOrigin){
    2331               0 :       aOrigin = nsGkAtoms::pixels;
    2332                 :     }
    2333               0 :     break;
    2334                 :   }
    2335                 :   case nsIScrollableFrame::LINES: {
    2336               0 :     deltaMultiplier = GetLineScrollAmount();
    2337               0 :     if (isGenericOrigin){
    2338               0 :       aOrigin = nsGkAtoms::lines;
    2339                 :     }
    2340               0 :     break;
    2341                 :   }
    2342                 :   case nsIScrollableFrame::PAGES: {
    2343               0 :     deltaMultiplier = GetPageScrollAmount();
    2344               0 :     if (isGenericOrigin){
    2345               0 :       aOrigin = nsGkAtoms::pages;
    2346                 :     }
    2347               0 :     break;
    2348                 :   }
    2349                 :   case nsIScrollableFrame::WHOLE: {
    2350               0 :     nsPoint pos = GetScrollPosition();
    2351               0 :     AdjustForWholeDelta(aDelta.x, &pos.x);
    2352               0 :     AdjustForWholeDelta(aDelta.y, &pos.y);
    2353               0 :     ScrollTo(pos, aMode);
    2354               0 :     if (aOverflow) {
    2355               0 :       *aOverflow = nsIntPoint(0, 0);
    2356                 :     }
    2357               0 :     return;
    2358                 :   }
    2359                 :   default:
    2360               0 :     NS_ERROR("Invalid scroll mode");
    2361               0 :     return;
    2362                 :   }
    2363                 : 
    2364                 :   nsPoint newPos = mDestination +
    2365               0 :     nsPoint(aDelta.x*deltaMultiplier.width, aDelta.y*deltaMultiplier.height);
    2366               0 :   ScrollToWithOrigin(newPos, aMode, aOrigin);
    2367                 : 
    2368               0 :   if (aOverflow) {
    2369               0 :     nsPoint clampAmount = mDestination - newPos;
    2370               0 :     float appUnitsPerDevPixel = mOuter->PresContext()->AppUnitsPerDevPixel();
    2371                 :     *aOverflow = nsIntPoint(
    2372                 :         NSAppUnitsToIntPixels(NS_ABS(clampAmount.x), appUnitsPerDevPixel),
    2373               0 :         NSAppUnitsToIntPixels(NS_ABS(clampAmount.y), appUnitsPerDevPixel));
    2374                 :   }
    2375                 : }
    2376                 : 
    2377                 : nsSize
    2378               0 : nsGfxScrollFrameInner::GetLineScrollAmount() const
    2379                 : {
    2380               0 :   nsRefPtr<nsFontMetrics> fm;
    2381                 :   nsLayoutUtils::GetFontMetricsForFrame(mOuter, getter_AddRefs(fm),
    2382               0 :     nsLayoutUtils::FontSizeInflationFor(mOuter, nsLayoutUtils::eNotInReflow));
    2383               0 :   NS_ASSERTION(fm, "FontMetrics is null, assuming fontHeight == 1 appunit");
    2384               0 :   nscoord fontHeight = 1;
    2385               0 :   if (fm) {
    2386               0 :     fontHeight = fm->MaxHeight();
    2387                 :   }
    2388                 : 
    2389               0 :   return nsSize(fontHeight, fontHeight);
    2390                 : }
    2391                 : 
    2392                 : nsSize
    2393               0 : nsGfxScrollFrameInner::GetPageScrollAmount() const
    2394                 : {
    2395               0 :   nsSize lineScrollAmount = GetLineScrollAmount();
    2396                 :   // The page increment is the size of the page, minus the smaller of
    2397                 :   // 10% of the size or 2 lines.
    2398                 :   return nsSize(
    2399               0 :     mScrollPort.width - NS_MIN(mScrollPort.width/10, 2*lineScrollAmount.width),
    2400               0 :     mScrollPort.height - NS_MIN(mScrollPort.height/10, 2*lineScrollAmount.height));
    2401                 : }
    2402                 : 
    2403                 :   /**
    2404                 :    * this code is resposible for restoring the scroll position back to some
    2405                 :    * saved position. if the user has not moved the scroll position manually
    2406                 :    * we keep scrolling down until we get to our original position. keep in
    2407                 :    * mind that content could incrementally be coming in. we only want to stop
    2408                 :    * when we reach our new position.
    2409                 :    */
    2410                 : void
    2411               0 : nsGfxScrollFrameInner::ScrollToRestoredPosition()
    2412                 : {
    2413               0 :   if (mRestorePos.y == -1 || mLastPos.x == -1 || mLastPos.y == -1) {
    2414               0 :     return;
    2415                 :   }
    2416                 :   // make sure our scroll position did not change for where we last put
    2417                 :   // it. if it does then the user must have moved it, and we no longer
    2418                 :   // need to restore.
    2419                 :   //
    2420                 :   // In the RTL case, we check whether the scroll position changed using the
    2421                 :   // logical scroll position, but we scroll to the physical scroll position in
    2422                 :   // all cases
    2423                 : 
    2424                 :   // if we didn't move, we still need to restore
    2425               0 :   if (GetLogicalScrollPosition() == mLastPos) {
    2426                 :     // if our desired position is different to the scroll position, scroll.
    2427                 :     // remember that we could be incrementally loading so we may enter
    2428                 :     // and scroll many times.
    2429               0 :     if (mRestorePos != mLastPos /* GetLogicalScrollPosition() */) {
    2430               0 :       nsPoint scrollToPos = mRestorePos;
    2431               0 :       if (!IsLTR())
    2432                 :         // convert from logical to physical scroll position
    2433                 :         scrollToPos.x = mScrollPort.x - 
    2434               0 :           (mScrollPort.XMost() - scrollToPos.x - mScrolledFrame->GetRect().width);
    2435               0 :       ScrollTo(scrollToPos, nsIScrollableFrame::INSTANT);
    2436                 :       // Re-get the scroll position, it might not be exactly equal to
    2437                 :       // mRestorePos due to rounding and clamping.
    2438               0 :       mLastPos = GetLogicalScrollPosition();
    2439                 :     } else {
    2440                 :       // if we reached the position then stop
    2441               0 :       mRestorePos.y = -1;
    2442               0 :       mLastPos.x = -1;
    2443               0 :       mLastPos.y = -1;
    2444                 :     }
    2445                 :   } else {
    2446                 :     // user moved the position, so we won't need to restore
    2447               0 :     mLastPos.x = -1;
    2448               0 :     mLastPos.y = -1;
    2449                 :   }
    2450                 : }
    2451                 : 
    2452                 : nsresult
    2453               0 : nsGfxScrollFrameInner::FireScrollPortEvent()
    2454                 : {
    2455               0 :   mAsyncScrollPortEvent.Forget();
    2456                 : 
    2457                 :   // Keep this in sync with PostOverflowEvent().
    2458               0 :   nsSize scrollportSize = mScrollPort.Size();
    2459               0 :   nsSize childSize = GetScrolledRect().Size();
    2460                 : 
    2461               0 :   bool newVerticalOverflow = childSize.height > scrollportSize.height;
    2462               0 :   bool vertChanged = mVerticalOverflow != newVerticalOverflow;
    2463                 : 
    2464               0 :   bool newHorizontalOverflow = childSize.width > scrollportSize.width;
    2465               0 :   bool horizChanged = mHorizontalOverflow != newHorizontalOverflow;
    2466                 : 
    2467               0 :   if (!vertChanged && !horizChanged) {
    2468               0 :     return NS_OK;
    2469                 :   }
    2470                 : 
    2471                 :   // If both either overflowed or underflowed then we dispatch only one
    2472                 :   // DOM event.
    2473                 :   bool both = vertChanged && horizChanged &&
    2474               0 :                 newVerticalOverflow == newHorizontalOverflow;
    2475                 :   nsScrollPortEvent::orientType orient;
    2476               0 :   if (both) {
    2477               0 :     orient = nsScrollPortEvent::both;
    2478               0 :     mHorizontalOverflow = newHorizontalOverflow;
    2479               0 :     mVerticalOverflow = newVerticalOverflow;
    2480                 :   }
    2481               0 :   else if (vertChanged) {
    2482               0 :     orient = nsScrollPortEvent::vertical;
    2483               0 :     mVerticalOverflow = newVerticalOverflow;
    2484               0 :     if (horizChanged) {
    2485                 :       // We need to dispatch a separate horizontal DOM event. Do that the next
    2486                 :       // time around since dispatching the vertical DOM event might destroy
    2487                 :       // the frame.
    2488               0 :       PostOverflowEvent();
    2489                 :     }
    2490                 :   }
    2491                 :   else {
    2492               0 :     orient = nsScrollPortEvent::horizontal;
    2493               0 :     mHorizontalOverflow = newHorizontalOverflow;
    2494                 :   }
    2495                 : 
    2496                 :   nsScrollPortEvent event(true,
    2497                 :                           (orient == nsScrollPortEvent::horizontal ?
    2498                 :                            mHorizontalOverflow : mVerticalOverflow) ?
    2499                 :                             NS_SCROLLPORT_OVERFLOW : NS_SCROLLPORT_UNDERFLOW,
    2500               0 :                           nsnull);
    2501               0 :   event.orient = orient;
    2502               0 :   return nsEventDispatcher::Dispatch(mOuter->GetContent(),
    2503               0 :                                      mOuter->PresContext(), &event);
    2504                 : }
    2505                 : 
    2506                 : void
    2507               0 : nsGfxScrollFrameInner::ReloadChildFrames()
    2508                 : {
    2509               0 :   mScrolledFrame = nsnull;
    2510               0 :   mHScrollbarBox = nsnull;
    2511               0 :   mVScrollbarBox = nsnull;
    2512               0 :   mScrollCornerBox = nsnull;
    2513               0 :   mResizerBox = nsnull;
    2514                 : 
    2515               0 :   nsIFrame* frame = mOuter->GetFirstPrincipalChild();
    2516               0 :   while (frame) {
    2517               0 :     nsIContent* content = frame->GetContent();
    2518               0 :     if (content == mOuter->GetContent()) {
    2519               0 :       NS_ASSERTION(!mScrolledFrame, "Already found the scrolled frame");
    2520               0 :       mScrolledFrame = frame;
    2521                 :     } else {
    2522               0 :       nsAutoString value;
    2523               0 :       content->GetAttr(kNameSpaceID_None, nsGkAtoms::orient, value);
    2524               0 :       if (!value.IsEmpty()) {
    2525                 :         // probably a scrollbar then
    2526               0 :         if (value.LowerCaseEqualsLiteral("horizontal")) {
    2527               0 :           NS_ASSERTION(!mHScrollbarBox, "Found multiple horizontal scrollbars?");
    2528               0 :           mHScrollbarBox = frame;
    2529                 :         } else {
    2530               0 :           NS_ASSERTION(!mVScrollbarBox, "Found multiple vertical scrollbars?");
    2531               0 :           mVScrollbarBox = frame;
    2532                 :         }
    2533               0 :       } else if (content->Tag() == nsGkAtoms::resizer) {
    2534               0 :         NS_ASSERTION(!mResizerBox, "Found multiple resizers");
    2535               0 :         mResizerBox = frame;
    2536                 :       } else {
    2537                 :         // probably a scrollcorner
    2538               0 :         NS_ASSERTION(!mScrollCornerBox, "Found multiple scrollcorners");
    2539               0 :         mScrollCornerBox = frame;
    2540                 :       }
    2541                 :     }
    2542                 : 
    2543               0 :     frame = frame->GetNextSibling();
    2544                 :   }
    2545               0 : }
    2546                 :   
    2547                 : nsresult
    2548               0 : nsGfxScrollFrameInner::CreateAnonymousContent(
    2549                 :   nsTArray<nsIAnonymousContentCreator::ContentInfo>& aElements)
    2550                 : {
    2551               0 :   nsPresContext* presContext = mOuter->PresContext();
    2552               0 :   nsIFrame* parent = mOuter->GetParent();
    2553                 : 
    2554                 :   // Don't create scrollbars if we're an SVG document being used as an image,
    2555                 :   // or if we're printing/print previewing.
    2556                 :   // (In the printing case, we allow scrollbars if this is the child of the
    2557                 :   // viewport & paginated scrolling is enabled, because then we must be the
    2558                 :   // scroll frame for the print preview window, & that does need scrollbars.)
    2559               0 :   if (presContext->Document()->IsBeingUsedAsImage() ||
    2560               0 :       (!presContext->IsDynamic() &&
    2561               0 :        !(mIsRoot && presContext->HasPaginatedScrolling()))) {
    2562               0 :     mNeverHasVerticalScrollbar = mNeverHasHorizontalScrollbar = true;
    2563               0 :     return NS_OK;
    2564                 :   }
    2565                 : 
    2566                 :   // Check if the frame is resizable.
    2567               0 :   PRInt8 resizeStyle = mOuter->GetStyleDisplay()->mResize;
    2568               0 :   bool isResizable = resizeStyle != NS_STYLE_RESIZE_NONE;
    2569                 : 
    2570               0 :   nsIScrollableFrame *scrollable = do_QueryFrame(mOuter);
    2571                 : 
    2572                 :   // If we're the scrollframe for the root, then we want to construct
    2573                 :   // our scrollbar frames no matter what.  That way later dynamic
    2574                 :   // changes to propagated overflow styles will show or hide
    2575                 :   // scrollbars on the viewport without requiring frame reconstruction
    2576                 :   // of the viewport (good!).
    2577                 :   bool canHaveHorizontal;
    2578                 :   bool canHaveVertical;
    2579               0 :   if (!mIsRoot) {
    2580               0 :     ScrollbarStyles styles = scrollable->GetScrollbarStyles();
    2581               0 :     canHaveHorizontal = styles.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN;
    2582               0 :     canHaveVertical = styles.mVertical != NS_STYLE_OVERFLOW_HIDDEN;
    2583               0 :     if (!canHaveHorizontal && !canHaveVertical && !isResizable) {
    2584                 :       // Nothing to do.
    2585               0 :       return NS_OK;
    2586                 :     }
    2587                 :   } else {
    2588               0 :     canHaveHorizontal = true;
    2589               0 :     canHaveVertical = true;
    2590                 :   }
    2591                 : 
    2592                 :   // The anonymous <div> used by <inputs> never gets scrollbars.
    2593               0 :   nsITextControlFrame* textFrame = do_QueryFrame(parent);
    2594               0 :   if (textFrame) {
    2595                 :     // Make sure we are not a text area.
    2596               0 :     nsCOMPtr<nsIDOMHTMLTextAreaElement> textAreaElement(do_QueryInterface(parent->GetContent()));
    2597               0 :     if (!textAreaElement) {
    2598               0 :       mNeverHasVerticalScrollbar = mNeverHasHorizontalScrollbar = true;
    2599               0 :       return NS_OK;
    2600                 :     }
    2601                 :   }
    2602                 : 
    2603                 :   nsNodeInfoManager *nodeInfoManager =
    2604               0 :     presContext->Document()->NodeInfoManager();
    2605               0 :   nsCOMPtr<nsINodeInfo> nodeInfo;
    2606                 :   nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::scrollbar, nsnull,
    2607                 :                                           kNameSpaceID_XUL,
    2608               0 :                                           nsIDOMNode::ELEMENT_NODE);
    2609               0 :   NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
    2610                 : 
    2611               0 :   if (canHaveHorizontal) {
    2612               0 :     nsCOMPtr<nsINodeInfo> ni = nodeInfo;
    2613               0 :     NS_TrustedNewXULElement(getter_AddRefs(mHScrollbarContent), ni.forget());
    2614                 :     mHScrollbarContent->SetAttr(kNameSpaceID_None, nsGkAtoms::orient,
    2615               0 :                                 NS_LITERAL_STRING("horizontal"), false);
    2616                 :     mHScrollbarContent->SetAttr(kNameSpaceID_None, nsGkAtoms::clickthrough,
    2617               0 :                                 NS_LITERAL_STRING("always"), false);
    2618               0 :     if (!aElements.AppendElement(mHScrollbarContent))
    2619               0 :       return NS_ERROR_OUT_OF_MEMORY;
    2620                 :   }
    2621                 : 
    2622               0 :   if (canHaveVertical) {
    2623               0 :     nsCOMPtr<nsINodeInfo> ni = nodeInfo;
    2624               0 :     NS_TrustedNewXULElement(getter_AddRefs(mVScrollbarContent), ni.forget());
    2625                 :     mVScrollbarContent->SetAttr(kNameSpaceID_None, nsGkAtoms::orient,
    2626               0 :                                 NS_LITERAL_STRING("vertical"), false);
    2627                 :     mVScrollbarContent->SetAttr(kNameSpaceID_None, nsGkAtoms::clickthrough,
    2628               0 :                                 NS_LITERAL_STRING("always"), false);
    2629               0 :     if (!aElements.AppendElement(mVScrollbarContent))
    2630               0 :       return NS_ERROR_OUT_OF_MEMORY;
    2631                 :   }
    2632                 : 
    2633               0 :   if (isResizable) {
    2634               0 :     nsCOMPtr<nsINodeInfo> nodeInfo;
    2635                 :     nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::resizer, nsnull,
    2636                 :                                             kNameSpaceID_XUL,
    2637               0 :                                             nsIDOMNode::ELEMENT_NODE);
    2638               0 :     NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
    2639                 : 
    2640               0 :     NS_TrustedNewXULElement(getter_AddRefs(mResizerContent), nodeInfo.forget());
    2641                 : 
    2642               0 :     nsAutoString dir;
    2643               0 :     switch (resizeStyle) {
    2644                 :       case NS_STYLE_RESIZE_HORIZONTAL:
    2645               0 :         if (IsScrollbarOnRight()) {
    2646               0 :           dir.AssignLiteral("right");
    2647                 :         }
    2648                 :         else {
    2649               0 :           dir.AssignLiteral("left");
    2650                 :         }
    2651               0 :         break;
    2652                 :       case NS_STYLE_RESIZE_VERTICAL:
    2653               0 :         dir.AssignLiteral("bottom");
    2654               0 :         break;
    2655                 :       case NS_STYLE_RESIZE_BOTH:
    2656               0 :         dir.AssignLiteral("bottomend");
    2657               0 :         break;
    2658                 :       default:
    2659               0 :         NS_WARNING("only resizable types should have resizers");
    2660                 :     }
    2661               0 :     mResizerContent->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, dir, false);
    2662                 : 
    2663               0 :     if (mIsRoot) {
    2664               0 :       nsIContent* browserRoot = GetBrowserRoot(mOuter->GetContent());
    2665                 :       mCollapsedResizer = !(browserRoot &&
    2666               0 :                             browserRoot->HasAttr(kNameSpaceID_None, nsGkAtoms::showresizer));
    2667                 :     }
    2668                 :     else {
    2669                 :       mResizerContent->SetAttr(kNameSpaceID_None, nsGkAtoms::element,
    2670               0 :                                     NS_LITERAL_STRING("_parent"), false);
    2671                 :     }
    2672                 : 
    2673                 :     mResizerContent->SetAttr(kNameSpaceID_None, nsGkAtoms::clickthrough,
    2674               0 :                                   NS_LITERAL_STRING("always"), false);
    2675                 : 
    2676               0 :     if (!aElements.AppendElement(mResizerContent))
    2677               0 :       return NS_ERROR_OUT_OF_MEMORY;
    2678                 :   }
    2679                 : 
    2680               0 :   if (canHaveHorizontal && canHaveVertical) {
    2681                 :     nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::scrollcorner, nsnull,
    2682                 :                                             kNameSpaceID_XUL,
    2683               0 :                                             nsIDOMNode::ELEMENT_NODE);
    2684               0 :     NS_TrustedNewXULElement(getter_AddRefs(mScrollCornerContent), nodeInfo.forget());
    2685               0 :     if (!aElements.AppendElement(mScrollCornerContent))
    2686               0 :       return NS_ERROR_OUT_OF_MEMORY;
    2687                 :   }
    2688                 : 
    2689               0 :   return NS_OK;
    2690                 : }
    2691                 : 
    2692                 : void
    2693               0 : nsGfxScrollFrameInner::AppendAnonymousContentTo(nsBaseContentList& aElements,
    2694                 :                                                 PRUint32 aFilter)
    2695                 : {
    2696               0 :   aElements.MaybeAppendElement(mHScrollbarContent);
    2697               0 :   aElements.MaybeAppendElement(mVScrollbarContent);
    2698               0 :   aElements.MaybeAppendElement(mScrollCornerContent);
    2699               0 :   aElements.MaybeAppendElement(mResizerContent);
    2700               0 : }
    2701                 : 
    2702                 : void
    2703               0 : nsGfxScrollFrameInner::Destroy()
    2704                 : {
    2705                 :   // Unbind any content created in CreateAnonymousContent from the tree
    2706               0 :   nsContentUtils::DestroyAnonymousContent(&mHScrollbarContent);
    2707               0 :   nsContentUtils::DestroyAnonymousContent(&mVScrollbarContent);
    2708               0 :   nsContentUtils::DestroyAnonymousContent(&mScrollCornerContent);
    2709               0 :   nsContentUtils::DestroyAnonymousContent(&mResizerContent);
    2710                 : 
    2711               0 :   if (mPostedReflowCallback) {
    2712               0 :     mOuter->PresContext()->PresShell()->CancelReflowCallback(this);
    2713               0 :     mPostedReflowCallback = false;
    2714                 :   }
    2715               0 : }
    2716                 : 
    2717                 : /**
    2718                 :  * Called when we want to update the scrollbar position, either because scrolling happened
    2719                 :  * or the user moved the scrollbar position and we need to undo that (e.g., when the user
    2720                 :  * clicks to scroll and we're using smooth scrolling, so we need to put the thumb back
    2721                 :  * to its initial position for the start of the smooth sequence).
    2722                 :  */
    2723                 : void
    2724               0 : nsGfxScrollFrameInner::UpdateScrollbarPosition()
    2725                 : {
    2726               0 :   mFrameIsUpdatingScrollbar = true;
    2727                 : 
    2728               0 :   nsPoint pt = GetScrollPosition();
    2729               0 :   if (mVScrollbarBox) {
    2730                 :     SetCoordAttribute(mVScrollbarBox->GetContent(), nsGkAtoms::curpos,
    2731               0 :                       pt.y - GetScrolledRect().y);
    2732                 :   }
    2733               0 :   if (mHScrollbarBox) {
    2734                 :     SetCoordAttribute(mHScrollbarBox->GetContent(), nsGkAtoms::curpos,
    2735               0 :                       pt.x - GetScrolledRect().x);
    2736                 :   }
    2737                 : 
    2738               0 :   mFrameIsUpdatingScrollbar = false;
    2739               0 : }
    2740                 : 
    2741               0 : void nsGfxScrollFrameInner::CurPosAttributeChanged(nsIContent* aContent)
    2742                 : {
    2743               0 :   NS_ASSERTION(aContent, "aContent must not be null");
    2744               0 :   NS_ASSERTION((mHScrollbarBox && mHScrollbarBox->GetContent() == aContent) ||
    2745                 :                (mVScrollbarBox && mVScrollbarBox->GetContent() == aContent),
    2746                 :                "unexpected child");
    2747                 : 
    2748                 :   // Attribute changes on the scrollbars happen in one of three ways:
    2749                 :   // 1) The scrollbar changed the attribute in response to some user event
    2750                 :   // 2) We changed the attribute in response to a ScrollPositionDidChange
    2751                 :   // callback from the scrolling view
    2752                 :   // 3) We changed the attribute to adjust the scrollbars for the start
    2753                 :   // of a smooth scroll operation
    2754                 :   //
    2755                 :   // In cases 2 and 3 we do not need to scroll because we're just
    2756                 :   // updating our scrollbar.
    2757               0 :   if (mFrameIsUpdatingScrollbar)
    2758               0 :     return;
    2759                 : 
    2760               0 :   nsRect scrolledRect = GetScrolledRect();
    2761                 : 
    2762               0 :   nsPoint current = GetScrollPosition() - scrolledRect.TopLeft();
    2763               0 :   nsPoint dest;
    2764               0 :   dest.x = GetCoordAttribute(mHScrollbarBox, nsGkAtoms::curpos, current.x) +
    2765               0 :            scrolledRect.x;
    2766               0 :   dest.y = GetCoordAttribute(mVScrollbarBox, nsGkAtoms::curpos, current.y) +
    2767               0 :            scrolledRect.y;
    2768                 : 
    2769                 :   // If we have an async scroll pending don't stomp on that by calling ScrollTo.
    2770               0 :   if (mAsyncScroll && dest == GetScrollPosition()) {
    2771                 :     return;
    2772                 :   }
    2773                 : 
    2774               0 :   bool isSmooth = aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::smooth);
    2775               0 :   if (isSmooth) {
    2776                 :     // Make sure an attribute-setting callback occurs even if the view
    2777                 :     // didn't actually move yet.  We need to make sure other listeners
    2778                 :     // see that the scroll position is not (yet) what they thought it
    2779                 :     // was.
    2780               0 :     UpdateScrollbarPosition();
    2781                 :   }
    2782                 :   ScrollToWithOrigin(dest,
    2783                 :                      isSmooth ? nsIScrollableFrame::SMOOTH : nsIScrollableFrame::INSTANT,
    2784               0 :                      nsGkAtoms::scrollbars);
    2785                 : }
    2786                 : 
    2787                 : /* ============= Scroll events ========== */
    2788                 : 
    2789                 : NS_IMETHODIMP
    2790               0 : nsGfxScrollFrameInner::ScrollEvent::Run()
    2791                 : {
    2792               0 :   if (mInner)
    2793               0 :     mInner->FireScrollEvent();
    2794               0 :   return NS_OK;
    2795                 : }
    2796                 : 
    2797                 : void
    2798               0 : nsGfxScrollFrameInner::FireScrollEvent()
    2799                 : {
    2800               0 :   mScrollEvent.Forget();
    2801                 : 
    2802               0 :   nsScrollbarEvent event(true, NS_SCROLL_EVENT, nsnull);
    2803               0 :   nsEventStatus status = nsEventStatus_eIgnore;
    2804               0 :   nsIContent* content = mOuter->GetContent();
    2805               0 :   nsPresContext* prescontext = mOuter->PresContext();
    2806                 :   // Fire viewport scroll events at the document (where they
    2807                 :   // will bubble to the window)
    2808               0 :   if (mIsRoot) {
    2809               0 :     nsIDocument* doc = content->GetCurrentDoc();
    2810               0 :     if (doc) {
    2811               0 :       nsEventDispatcher::Dispatch(doc, prescontext, &event, nsnull,  &status);
    2812                 :     }
    2813                 :   } else {
    2814                 :     // scroll events fired at elements don't bubble (although scroll events
    2815                 :     // fired at documents do, to the window)
    2816               0 :     event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
    2817               0 :     nsEventDispatcher::Dispatch(content, prescontext, &event, nsnull, &status);
    2818                 :   }
    2819               0 : }
    2820                 : 
    2821                 : void
    2822               0 : nsGfxScrollFrameInner::PostScrollEvent()
    2823                 : {
    2824               0 :   if (mScrollEvent.IsPending())
    2825               0 :     return;
    2826                 : 
    2827               0 :   nsRootPresContext* rpc = mOuter->PresContext()->GetRootPresContext();
    2828               0 :   if (!rpc)
    2829               0 :     return;
    2830               0 :   mScrollEvent = new ScrollEvent(this);
    2831               0 :   rpc->AddWillPaintObserver(mScrollEvent.get());
    2832                 : }
    2833                 : 
    2834                 : NS_IMETHODIMP
    2835               0 : nsGfxScrollFrameInner::AsyncScrollPortEvent::Run()
    2836                 : {
    2837               0 :   if (mInner) {
    2838               0 :     mInner->mOuter->PresContext()->GetPresShell()->
    2839               0 :       FlushPendingNotifications(Flush_InterruptibleLayout);
    2840                 :   }
    2841               0 :   return mInner ? mInner->FireScrollPortEvent() : NS_OK;
    2842                 : }
    2843                 : 
    2844                 : bool
    2845               0 : nsXULScrollFrame::AddHorizontalScrollbar(nsBoxLayoutState& aState, bool aOnBottom)
    2846                 : {
    2847               0 :   if (!mInner.mHScrollbarBox)
    2848               0 :     return true;
    2849                 : 
    2850               0 :   return AddRemoveScrollbar(aState, aOnBottom, true, true);
    2851                 : }
    2852                 : 
    2853                 : bool
    2854               0 : nsXULScrollFrame::AddVerticalScrollbar(nsBoxLayoutState& aState, bool aOnRight)
    2855                 : {
    2856               0 :   if (!mInner.mVScrollbarBox)
    2857               0 :     return true;
    2858                 : 
    2859               0 :   return AddRemoveScrollbar(aState, aOnRight, false, true);
    2860                 : }
    2861                 : 
    2862                 : void
    2863               0 : nsXULScrollFrame::RemoveHorizontalScrollbar(nsBoxLayoutState& aState, bool aOnBottom)
    2864                 : {
    2865                 :   // removing a scrollbar should always fit
    2866                 : #ifdef DEBUG
    2867                 :   bool result =
    2868                 : #endif
    2869               0 :   AddRemoveScrollbar(aState, aOnBottom, true, false);
    2870               0 :   NS_ASSERTION(result, "Removing horizontal scrollbar failed to fit??");
    2871               0 : }
    2872                 : 
    2873                 : void
    2874               0 : nsXULScrollFrame::RemoveVerticalScrollbar(nsBoxLayoutState& aState, bool aOnRight)
    2875                 : {
    2876                 :   // removing a scrollbar should always fit
    2877                 : #ifdef DEBUG
    2878                 :   bool result =
    2879                 : #endif
    2880               0 :   AddRemoveScrollbar(aState, aOnRight, false, false);
    2881               0 :   NS_ASSERTION(result, "Removing vertical scrollbar failed to fit??");
    2882               0 : }
    2883                 : 
    2884                 : bool
    2885               0 : nsXULScrollFrame::AddRemoveScrollbar(nsBoxLayoutState& aState,
    2886                 :                                      bool aOnRightOrBottom, bool aHorizontal, bool aAdd)
    2887                 : {
    2888               0 :   if (aHorizontal) {
    2889               0 :      if (mInner.mNeverHasHorizontalScrollbar || !mInner.mHScrollbarBox)
    2890               0 :        return false;
    2891                 : 
    2892               0 :      nsSize hSize = mInner.mHScrollbarBox->GetPrefSize(aState);
    2893               0 :      nsBox::AddMargin(mInner.mHScrollbarBox, hSize);
    2894                 : 
    2895               0 :      mInner.SetScrollbarVisibility(mInner.mHScrollbarBox, aAdd);
    2896                 : 
    2897                 :      bool hasHorizontalScrollbar;
    2898                 :      bool fit = AddRemoveScrollbar(hasHorizontalScrollbar,
    2899                 :                                      mInner.mScrollPort.y,
    2900                 :                                      mInner.mScrollPort.height,
    2901               0 :                                      hSize.height, aOnRightOrBottom, aAdd);
    2902               0 :      mInner.mHasHorizontalScrollbar = hasHorizontalScrollbar;    // because mHasHorizontalScrollbar is a bool
    2903               0 :      if (!fit)
    2904               0 :         mInner.SetScrollbarVisibility(mInner.mHScrollbarBox, !aAdd);
    2905                 : 
    2906               0 :      return fit;
    2907                 :   } else {
    2908               0 :      if (mInner.mNeverHasVerticalScrollbar || !mInner.mVScrollbarBox)
    2909               0 :        return false;
    2910                 : 
    2911               0 :      nsSize vSize = mInner.mVScrollbarBox->GetPrefSize(aState);
    2912               0 :      nsBox::AddMargin(mInner.mVScrollbarBox, vSize);
    2913                 : 
    2914               0 :      mInner.SetScrollbarVisibility(mInner.mVScrollbarBox, aAdd);
    2915                 : 
    2916                 :      bool hasVerticalScrollbar;
    2917                 :      bool fit = AddRemoveScrollbar(hasVerticalScrollbar,
    2918                 :                                      mInner.mScrollPort.x,
    2919                 :                                      mInner.mScrollPort.width,
    2920               0 :                                      vSize.width, aOnRightOrBottom, aAdd);
    2921               0 :      mInner.mHasVerticalScrollbar = hasVerticalScrollbar;    // because mHasVerticalScrollbar is a bool
    2922               0 :      if (!fit)
    2923               0 :         mInner.SetScrollbarVisibility(mInner.mVScrollbarBox, !aAdd);
    2924                 : 
    2925               0 :      return fit;
    2926                 :   }
    2927                 : }
    2928                 : 
    2929                 : bool
    2930               0 : nsXULScrollFrame::AddRemoveScrollbar(bool& aHasScrollbar, nscoord& aXY,
    2931                 :                                      nscoord& aSize, nscoord aSbSize,
    2932                 :                                      bool aOnRightOrBottom, bool aAdd)
    2933                 : { 
    2934               0 :    nscoord size = aSize;
    2935               0 :    nscoord xy = aXY;
    2936                 : 
    2937               0 :    if (size != NS_INTRINSICSIZE) {
    2938               0 :      if (aAdd) {
    2939               0 :         size -= aSbSize;
    2940               0 :         if (!aOnRightOrBottom && size >= 0)
    2941               0 :           xy += aSbSize;
    2942                 :      } else {
    2943               0 :         size += aSbSize;
    2944               0 :         if (!aOnRightOrBottom)
    2945               0 :           xy -= aSbSize;
    2946                 :      }
    2947                 :    }
    2948                 : 
    2949                 :    // not enough room? Yes? Return true.
    2950               0 :    if (size >= 0) {
    2951               0 :        aHasScrollbar = aAdd;
    2952               0 :        aSize = size;
    2953               0 :        aXY = xy;
    2954               0 :        return true;
    2955                 :    }
    2956                 : 
    2957               0 :    aHasScrollbar = false;
    2958               0 :    return false;
    2959                 : }
    2960                 : 
    2961                 : void
    2962               0 : nsXULScrollFrame::LayoutScrollArea(nsBoxLayoutState& aState,
    2963                 :                                    const nsPoint& aScrollPosition)
    2964                 : {
    2965               0 :   PRUint32 oldflags = aState.LayoutFlags();
    2966                 :   nsRect childRect = nsRect(mInner.mScrollPort.TopLeft() - aScrollPosition,
    2967               0 :                             mInner.mScrollPort.Size());
    2968               0 :   PRInt32 flags = NS_FRAME_NO_MOVE_VIEW;
    2969                 : 
    2970               0 :   nsRect originalRect = mInner.mScrolledFrame->GetRect();
    2971               0 :   nsRect originalVisOverflow = mInner.mScrolledFrame->GetVisualOverflowRect();
    2972                 : 
    2973               0 :   nsSize minSize = mInner.mScrolledFrame->GetMinSize(aState);
    2974                 :   
    2975               0 :   if (minSize.height > childRect.height)
    2976               0 :     childRect.height = minSize.height;
    2977                 :   
    2978               0 :   if (minSize.width > childRect.width)
    2979               0 :     childRect.width = minSize.width;
    2980                 : 
    2981               0 :   aState.SetLayoutFlags(flags);
    2982               0 :   ClampAndSetBounds(aState, childRect, aScrollPosition);
    2983               0 :   mInner.mScrolledFrame->Layout(aState);
    2984                 : 
    2985               0 :   childRect = mInner.mScrolledFrame->GetRect();
    2986                 : 
    2987               0 :   if (childRect.width < mInner.mScrollPort.width ||
    2988                 :       childRect.height < mInner.mScrollPort.height)
    2989                 :   {
    2990               0 :     childRect.width = NS_MAX(childRect.width, mInner.mScrollPort.width);
    2991               0 :     childRect.height = NS_MAX(childRect.height, mInner.mScrollPort.height);
    2992                 : 
    2993                 :     // remove overflow areas when we update the bounds,
    2994                 :     // because we've already accounted for it
    2995                 :     // REVIEW: Have we accounted for both?
    2996               0 :     ClampAndSetBounds(aState, childRect, aScrollPosition, true);
    2997                 :   }
    2998                 : 
    2999               0 :   nsRect finalRect = mInner.mScrolledFrame->GetRect();
    3000               0 :   nsRect finalVisOverflow = mInner.mScrolledFrame->GetVisualOverflowRect();
    3001                 :   // The position of the scrolled frame shouldn't change, but if it does or
    3002                 :   // the position of the overflow rect changes just invalidate both the old
    3003                 :   // and new overflow rect.
    3004               0 :   if (originalRect.TopLeft() != finalRect.TopLeft() ||
    3005               0 :       originalVisOverflow.TopLeft() != finalVisOverflow.TopLeft())
    3006                 :   {
    3007                 :     // The old overflow rect needs to be adjusted if the frame's position
    3008                 :     // changed.
    3009                 :     mInner.mScrolledFrame->Invalidate(
    3010               0 :       originalVisOverflow + originalRect.TopLeft() - finalRect.TopLeft());
    3011               0 :     mInner.mScrolledFrame->Invalidate(finalVisOverflow);
    3012               0 :   } else if (!originalVisOverflow.IsEqualInterior(finalVisOverflow)) {
    3013                 :     // If the overflow rect changed then invalidate the difference between the
    3014                 :     // old and new overflow rects.
    3015                 :     mInner.mScrolledFrame->CheckInvalidateSizeChange(
    3016               0 :       originalRect, originalVisOverflow, finalRect.Size());
    3017                 :     mInner.mScrolledFrame->InvalidateRectDifference(
    3018               0 :       originalVisOverflow, finalVisOverflow);
    3019                 :   }
    3020                 : 
    3021               0 :   aState.SetLayoutFlags(oldflags);
    3022                 : 
    3023               0 : }
    3024                 : 
    3025               0 : void nsGfxScrollFrameInner::PostOverflowEvent()
    3026                 : {
    3027               0 :   if (mAsyncScrollPortEvent.IsPending())
    3028               0 :     return;
    3029                 : 
    3030                 :   // Keep this in sync with FireScrollPortEvent().
    3031               0 :   nsSize scrollportSize = mScrollPort.Size();
    3032               0 :   nsSize childSize = GetScrolledRect().Size();
    3033                 : 
    3034               0 :   bool newVerticalOverflow = childSize.height > scrollportSize.height;
    3035               0 :   bool vertChanged = mVerticalOverflow != newVerticalOverflow;
    3036                 : 
    3037               0 :   bool newHorizontalOverflow = childSize.width > scrollportSize.width;
    3038               0 :   bool horizChanged = mHorizontalOverflow != newHorizontalOverflow;
    3039                 : 
    3040               0 :   if (!vertChanged && !horizChanged) {
    3041               0 :     return;
    3042                 :   }
    3043                 : 
    3044               0 :   nsRefPtr<AsyncScrollPortEvent> ev = new AsyncScrollPortEvent(this);
    3045               0 :   if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev)))
    3046               0 :     mAsyncScrollPortEvent = ev;
    3047                 : }
    3048                 : 
    3049                 : bool
    3050               0 : nsGfxScrollFrameInner::IsLTR() const
    3051                 : {
    3052                 :   //TODO make bidi code set these from preferences
    3053                 : 
    3054               0 :   nsIFrame *frame = mOuter;
    3055                 :   // XXX This is a bit on the slow side.
    3056               0 :   if (mIsRoot) {
    3057                 :     // If we're the root scrollframe, we need the root element's style data.
    3058               0 :     nsPresContext *presContext = mOuter->PresContext();
    3059               0 :     nsIDocument *document = presContext->Document();
    3060               0 :     Element *root = document->GetRootElement();
    3061                 : 
    3062                 :     // But for HTML and XHTML we want the body element.
    3063               0 :     nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(document);
    3064               0 :     if (htmlDoc) {
    3065               0 :       Element *bodyElement = document->GetBodyElement();
    3066               0 :       if (bodyElement)
    3067               0 :         root = bodyElement; // we can trust the document to hold on to it
    3068                 :     }
    3069                 : 
    3070               0 :     if (root) {
    3071               0 :       nsIFrame *rootsFrame = root->GetPrimaryFrame();
    3072               0 :       if (rootsFrame)
    3073               0 :         frame = rootsFrame;
    3074                 :     }
    3075                 :   }
    3076                 : 
    3077               0 :   return frame->GetStyleVisibility()->mDirection != NS_STYLE_DIRECTION_RTL;
    3078                 : }
    3079                 : 
    3080                 : bool
    3081               0 : nsGfxScrollFrameInner::IsScrollbarOnRight() const
    3082                 : {
    3083               0 :   nsPresContext *presContext = mOuter->PresContext();
    3084                 : 
    3085                 :   // The position of the scrollbar in top-level windows depends on the pref
    3086                 :   // layout.scrollbar.side. For non-top-level elements, it depends only on the
    3087                 :   // directionaliy of the element (equivalent to a value of "1" for the pref).
    3088               0 :   if (!mIsRoot)
    3089               0 :     return IsLTR();
    3090               0 :   switch (presContext->GetCachedIntPref(kPresContext_ScrollbarSide)) {
    3091                 :     default:
    3092                 :     case 0: // UI directionality
    3093               0 :       return presContext->GetCachedIntPref(kPresContext_BidiDirection)
    3094               0 :              == IBMBIDI_TEXTDIRECTION_LTR;
    3095                 :     case 1: // Document / content directionality
    3096               0 :       return IsLTR();
    3097                 :     case 2: // Always right
    3098               0 :       return true;
    3099                 :     case 3: // Always left
    3100               0 :       return false;
    3101                 :   }
    3102                 : }
    3103                 : 
    3104                 : /**
    3105                 :  * Reflow the scroll area if it needs it and return its size. Also determine if the reflow will
    3106                 :  * cause any of the scrollbars to need to be reflowed.
    3107                 :  */
    3108                 : nsresult
    3109               0 : nsXULScrollFrame::Layout(nsBoxLayoutState& aState)
    3110                 : {
    3111               0 :   bool scrollbarRight = mInner.IsScrollbarOnRight();
    3112               0 :   bool scrollbarBottom = true;
    3113                 : 
    3114                 :   // get the content rect
    3115               0 :   nsRect clientRect(0,0,0,0);
    3116               0 :   GetClientRect(clientRect);
    3117                 : 
    3118               0 :   nsRect oldScrollAreaBounds = mInner.mScrollPort;
    3119               0 :   nsPoint oldScrollPosition = mInner.GetLogicalScrollPosition();
    3120                 : 
    3121                 :   // the scroll area size starts off as big as our content area
    3122               0 :   mInner.mScrollPort = clientRect;
    3123                 : 
    3124                 :   /**************
    3125                 :    Our basic strategy here is to first try laying out the content with
    3126                 :    the scrollbars in their current state. We're hoping that that will
    3127                 :    just "work"; the content will overflow wherever there's a scrollbar
    3128                 :    already visible. If that does work, then there's no need to lay out
    3129                 :    the scrollarea. Otherwise we fix up the scrollbars; first we add a
    3130                 :    vertical one to scroll the content if necessary, or remove it if
    3131                 :    it's not needed. Then we reflow the content if the scrollbar
    3132                 :    changed.  Then we add a horizontal scrollbar if necessary (or
    3133                 :    remove if not needed), and if that changed, we reflow the content
    3134                 :    again. At this point, any scrollbars that are needed to scroll the
    3135                 :    content have been added.
    3136                 : 
    3137                 :    In the second phase we check to see if any scrollbars are too small
    3138                 :    to display, and if so, we remove them. We check the horizontal
    3139                 :    scrollbar first; removing it might make room for the vertical
    3140                 :    scrollbar, and if we have room for just one scrollbar we'll save
    3141                 :    the vertical one.
    3142                 : 
    3143                 :    Finally we position and size the scrollbars and scrollcorner (the
    3144                 :    square that is needed in the corner of the window when two
    3145                 :    scrollbars are visible), and reflow any fixed position views
    3146                 :    (if we're the viewport and we added or removed a scrollbar).
    3147                 :    **************/
    3148                 : 
    3149               0 :   ScrollbarStyles styles = GetScrollbarStyles();
    3150                 : 
    3151                 :   // Look at our style do we always have vertical or horizontal scrollbars?
    3152               0 :   if (styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL)
    3153               0 :      mInner.mHasHorizontalScrollbar = true;
    3154               0 :   if (styles.mVertical == NS_STYLE_OVERFLOW_SCROLL)
    3155               0 :      mInner.mHasVerticalScrollbar = true;
    3156                 : 
    3157               0 :   if (mInner.mHasHorizontalScrollbar)
    3158               0 :      AddHorizontalScrollbar(aState, scrollbarBottom);
    3159                 : 
    3160               0 :   if (mInner.mHasVerticalScrollbar)
    3161               0 :      AddVerticalScrollbar(aState, scrollbarRight);
    3162                 :      
    3163                 :   // layout our the scroll area
    3164               0 :   LayoutScrollArea(aState, oldScrollPosition);
    3165                 :   
    3166                 :   // now look at the content area and see if we need scrollbars or not
    3167               0 :   bool needsLayout = false;
    3168                 : 
    3169                 :   // if we have 'auto' scrollbars look at the vertical case
    3170               0 :   if (styles.mVertical != NS_STYLE_OVERFLOW_SCROLL) {
    3171                 :     // These are only good until the call to LayoutScrollArea.
    3172               0 :     nsRect scrolledRect = mInner.GetScrolledRect();
    3173                 : 
    3174                 :     // There are two cases to consider
    3175               0 :       if (scrolledRect.height <= mInner.mScrollPort.height
    3176                 :           || styles.mVertical != NS_STYLE_OVERFLOW_AUTO) {
    3177               0 :         if (mInner.mHasVerticalScrollbar) {
    3178                 :           // We left room for the vertical scrollbar, but it's not needed;
    3179                 :           // remove it.
    3180               0 :           RemoveVerticalScrollbar(aState, scrollbarRight);
    3181               0 :           needsLayout = true;
    3182                 :         }
    3183                 :       } else {
    3184               0 :         if (!mInner.mHasVerticalScrollbar) {
    3185                 :           // We didn't leave room for the vertical scrollbar, but it turns
    3186                 :           // out we needed it
    3187               0 :           if (AddVerticalScrollbar(aState, scrollbarRight))
    3188               0 :             needsLayout = true;
    3189                 :         }
    3190                 :     }
    3191                 : 
    3192                 :     // ok layout at the right size
    3193               0 :     if (needsLayout) {
    3194               0 :        nsBoxLayoutState resizeState(aState);
    3195               0 :        LayoutScrollArea(resizeState, oldScrollPosition);
    3196               0 :        needsLayout = false;
    3197                 :     }
    3198                 :   }
    3199                 : 
    3200                 : 
    3201                 :   // if scrollbars are auto look at the horizontal case
    3202               0 :   if (styles.mHorizontal != NS_STYLE_OVERFLOW_SCROLL)
    3203                 :   {
    3204                 :     // These are only good until the call to LayoutScrollArea.
    3205               0 :     nsRect scrolledRect = mInner.GetScrolledRect();
    3206                 : 
    3207                 :     // if the child is wider that the scroll area
    3208                 :     // and we don't have a scrollbar add one.
    3209               0 :     if ((scrolledRect.width > mInner.mScrollPort.width)
    3210                 :         && styles.mHorizontal == NS_STYLE_OVERFLOW_AUTO) {
    3211                 : 
    3212               0 :       if (!mInner.mHasHorizontalScrollbar) {
    3213                 :            // no scrollbar? 
    3214               0 :           if (AddHorizontalScrollbar(aState, scrollbarBottom))
    3215               0 :              needsLayout = true;
    3216                 : 
    3217                 :            // if we added a horizontal scrollbar and we did not have a vertical
    3218                 :            // there is a chance that by adding the horizontal scrollbar we will
    3219                 :            // suddenly need a vertical scrollbar. Is a special case but its 
    3220                 :            // important.
    3221                 :            //if (!mHasVerticalScrollbar && scrolledRect.height > scrollAreaRect.height - sbSize.height)
    3222                 :            //  printf("****Gfx Scrollbar Special case hit!!*****\n");
    3223                 :            
    3224                 :       }
    3225                 :     } else {
    3226                 :         // if the area is smaller or equal to and we have a scrollbar then
    3227                 :         // remove it.
    3228               0 :       if (mInner.mHasHorizontalScrollbar) {
    3229               0 :         RemoveHorizontalScrollbar(aState, scrollbarBottom);
    3230               0 :         needsLayout = true;
    3231                 :       }
    3232                 :     }
    3233                 :   }
    3234                 : 
    3235                 :   // we only need to set the rect. The inner child stays the same size.
    3236               0 :   if (needsLayout) {
    3237               0 :      nsBoxLayoutState resizeState(aState);
    3238               0 :      LayoutScrollArea(resizeState, oldScrollPosition);
    3239               0 :      needsLayout = false;
    3240                 :   }
    3241                 :     
    3242                 :   // get the preferred size of the scrollbars
    3243               0 :   nsSize hMinSize(0, 0);
    3244               0 :   if (mInner.mHScrollbarBox && mInner.mHasHorizontalScrollbar) {
    3245               0 :     GetScrollbarMetrics(aState, mInner.mHScrollbarBox, &hMinSize, nsnull, false);
    3246                 :   }
    3247               0 :   nsSize vMinSize(0, 0);
    3248               0 :   if (mInner.mVScrollbarBox && mInner.mHasVerticalScrollbar) {
    3249               0 :     GetScrollbarMetrics(aState, mInner.mVScrollbarBox, &vMinSize, nsnull, true);
    3250                 :   }
    3251                 : 
    3252                 :   // Disable scrollbars that are too small
    3253                 :   // Disable horizontal scrollbar first. If we have to disable only one
    3254                 :   // scrollbar, we'd rather keep the vertical scrollbar.
    3255                 :   // Note that we always give horizontal scrollbars their preferred height,
    3256                 :   // never their min-height. So check that there's room for the preferred height.
    3257               0 :   if (mInner.mHasHorizontalScrollbar &&
    3258                 :       (hMinSize.width > clientRect.width - vMinSize.width
    3259                 :        || hMinSize.height > clientRect.height)) {
    3260               0 :     RemoveHorizontalScrollbar(aState, scrollbarBottom);
    3261               0 :     needsLayout = true;
    3262                 :   }
    3263                 :   // Now disable vertical scrollbar if necessary
    3264               0 :   if (mInner.mHasVerticalScrollbar &&
    3265                 :       (vMinSize.height > clientRect.height - hMinSize.height
    3266                 :        || vMinSize.width > clientRect.width)) {
    3267               0 :     RemoveVerticalScrollbar(aState, scrollbarRight);
    3268               0 :     needsLayout = true;
    3269                 :   }
    3270                 : 
    3271                 :   // we only need to set the rect. The inner child stays the same size.
    3272               0 :   if (needsLayout) {
    3273               0 :     nsBoxLayoutState resizeState(aState);
    3274               0 :     LayoutScrollArea(resizeState, oldScrollPosition);
    3275                 :   }
    3276                 : 
    3277               0 :   if (!mInner.mSupppressScrollbarUpdate) { 
    3278               0 :     mInner.LayoutScrollbars(aState, clientRect, oldScrollAreaBounds);
    3279                 :   }
    3280               0 :   if (!mInner.mPostedReflowCallback) {
    3281                 :     // Make sure we'll try scrolling to restored position
    3282               0 :     PresContext()->PresShell()->PostReflowCallback(&mInner);
    3283               0 :     mInner.mPostedReflowCallback = true;
    3284                 :   }
    3285               0 :   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
    3286               0 :     mInner.mHadNonInitialReflow = true;
    3287                 :   }
    3288                 : 
    3289                 :   // Set up overflow areas for block frames for the benefit of
    3290                 :   // text-overflow.
    3291               0 :   nsIFrame* f = mInner.mScrolledFrame->GetContentInsertionFrame();
    3292               0 :   if (nsLayoutUtils::GetAsBlock(f)) {
    3293               0 :     nsRect origRect = f->GetRect();
    3294               0 :     nsRect clippedRect = origRect;
    3295               0 :     clippedRect.MoveBy(mInner.mScrollPort.TopLeft());
    3296               0 :     clippedRect.IntersectRect(clippedRect, mInner.mScrollPort);
    3297               0 :     nsOverflowAreas overflow = f->GetOverflowAreas();
    3298               0 :     f->FinishAndStoreOverflow(overflow, clippedRect.Size());
    3299               0 :     clippedRect.MoveTo(origRect.TopLeft());
    3300               0 :     f->SetRect(clippedRect);
    3301                 :   }
    3302                 : 
    3303               0 :   mInner.PostOverflowEvent();
    3304               0 :   return NS_OK;
    3305                 : }
    3306                 : 
    3307                 : void
    3308               0 : nsGfxScrollFrameInner::FinishReflowForScrollbar(nsIContent* aContent,
    3309                 :                                                 nscoord aMinXY, nscoord aMaxXY,
    3310                 :                                                 nscoord aCurPosXY,
    3311                 :                                                 nscoord aPageIncrement,
    3312                 :                                                 nscoord aIncrement)
    3313                 : {
    3314                 :   // Scrollbars assume zero is the minimum position, so translate for them.
    3315               0 :   SetCoordAttribute(aContent, nsGkAtoms::curpos, aCurPosXY - aMinXY);
    3316               0 :   SetScrollbarEnabled(aContent, aMaxXY - aMinXY);
    3317               0 :   SetCoordAttribute(aContent, nsGkAtoms::maxpos, aMaxXY - aMinXY);
    3318               0 :   SetCoordAttribute(aContent, nsGkAtoms::pageincrement, aPageIncrement);
    3319               0 :   SetCoordAttribute(aContent, nsGkAtoms::increment, aIncrement);
    3320               0 : }
    3321                 : 
    3322                 : bool
    3323               0 : nsGfxScrollFrameInner::ReflowFinished()
    3324                 : {
    3325               0 :   mPostedReflowCallback = false;
    3326                 : 
    3327               0 :   ScrollToRestoredPosition();
    3328                 : 
    3329                 :   // Clamp scroll position
    3330               0 :   ScrollToImpl(GetScrollPosition());
    3331                 : 
    3332               0 :   if (NS_SUBTREE_DIRTY(mOuter) || !mUpdateScrollbarAttributes)
    3333               0 :     return false;
    3334                 : 
    3335               0 :   mUpdateScrollbarAttributes = false;
    3336                 : 
    3337                 :   // Update scrollbar attributes.
    3338               0 :   nsPresContext* presContext = mOuter->PresContext();
    3339                 : 
    3340               0 :   if (mMayHaveDirtyFixedChildren) {
    3341               0 :     mMayHaveDirtyFixedChildren = false;
    3342               0 :     nsIFrame* parentFrame = mOuter->GetParent();
    3343               0 :     for (nsIFrame* fixedChild =
    3344               0 :            parentFrame->GetFirstChild(nsIFrame::kFixedList);
    3345                 :          fixedChild; fixedChild = fixedChild->GetNextSibling()) {
    3346                 :       // force a reflow of the fixed child
    3347               0 :       presContext->PresShell()->
    3348                 :         FrameNeedsReflow(fixedChild, nsIPresShell::eResize,
    3349               0 :                          NS_FRAME_HAS_DIRTY_CHILDREN);
    3350                 :     }
    3351                 :   }
    3352                 : 
    3353               0 :   nsRect scrolledContentRect = GetScrolledRect();
    3354               0 :   nscoord minX = scrolledContentRect.x;
    3355               0 :   nscoord maxX = scrolledContentRect.XMost() - mScrollPort.width;
    3356               0 :   nscoord minY = scrolledContentRect.y;
    3357               0 :   nscoord maxY = scrolledContentRect.YMost() - mScrollPort.height;
    3358                 : 
    3359                 :   // Suppress handling of the curpos attribute changes we make here.
    3360               0 :   NS_ASSERTION(!mFrameIsUpdatingScrollbar, "We shouldn't be reentering here");
    3361               0 :   mFrameIsUpdatingScrollbar = true;
    3362                 : 
    3363                 :   nsCOMPtr<nsIContent> vScroll =
    3364               0 :     mVScrollbarBox ? mVScrollbarBox->GetContent() : nsnull;
    3365                 :   nsCOMPtr<nsIContent> hScroll =
    3366               0 :     mHScrollbarBox ? mHScrollbarBox->GetContent() : nsnull;
    3367                 : 
    3368                 :   // Note, in some cases mOuter may get deleted while finishing reflow
    3369                 :   // for scrollbars.
    3370               0 :   if (vScroll || hScroll) {
    3371               0 :     nsWeakFrame weakFrame(mOuter);
    3372               0 :     nsPoint scrollPos = GetScrollPosition();
    3373                 :     // XXX shouldn't we use GetPageScrollAmount/GetLineScrollAmount here?
    3374               0 :     if (vScroll) {
    3375                 :       const double kScrollMultiplier = Preferences::GetInt("toolkit.scrollbox.verticalScrollDistance",
    3376               0 :                                                            NS_DEFAULT_VERTICAL_SCROLL_DISTANCE);
    3377               0 :       nscoord fontHeight = GetLineScrollAmount().height * kScrollMultiplier;
    3378                 :       // We normally use (scrollArea.height - fontHeight) for height
    3379                 :       // of page scrolling.  However, it is too small when
    3380                 :       // fontHeight is very large. (If fontHeight is larger than
    3381                 :       // scrollArea.height, direction of scrolling will be opposite).
    3382                 :       // To avoid it, we use (float(scrollArea.height) * 0.8) as
    3383                 :       // lower bound value of height of page scrolling. (bug 383267)
    3384               0 :       nscoord pageincrement = nscoord(mScrollPort.height - fontHeight);
    3385               0 :       nscoord pageincrementMin = nscoord(float(mScrollPort.height) * 0.8);
    3386                 :       FinishReflowForScrollbar(vScroll, minY, maxY, scrollPos.y,
    3387               0 :                                NS_MAX(pageincrement, pageincrementMin),
    3388               0 :                                fontHeight);
    3389                 :     }
    3390               0 :     if (hScroll) {
    3391                 :       FinishReflowForScrollbar(hScroll, minX, maxX, scrollPos.x,
    3392                 :                                nscoord(float(mScrollPort.width) * 0.8),
    3393               0 :                                nsPresContext::CSSPixelsToAppUnits(10));
    3394                 :     }
    3395               0 :     NS_ENSURE_TRUE(weakFrame.IsAlive(), false);
    3396                 :   }
    3397                 : 
    3398               0 :   mFrameIsUpdatingScrollbar = false;
    3399                 :   // We used to rely on the curpos attribute changes above to scroll the
    3400                 :   // view.  However, for scrolling to the left of the viewport, we
    3401                 :   // rescale the curpos attribute, which means that operations like
    3402                 :   // resizing the window while it is scrolled all the way to the left
    3403                 :   // hold the curpos attribute constant at 0 while still requiring
    3404                 :   // scrolling.  So we suppress the effect of the changes above with
    3405                 :   // mFrameIsUpdatingScrollbar and call CurPosAttributeChanged here.
    3406                 :   // (It actually even works some of the time without this, thanks to
    3407                 :   // nsSliderFrame::AttributeChanged's handling of maxpos, but not when
    3408                 :   // we hide the scrollbar on a large size change, such as
    3409                 :   // maximization.)
    3410               0 :   if (!mHScrollbarBox && !mVScrollbarBox)
    3411               0 :     return false;
    3412               0 :   CurPosAttributeChanged(mVScrollbarBox ? mVScrollbarBox->GetContent()
    3413               0 :                                         : mHScrollbarBox->GetContent());
    3414               0 :   return true;
    3415                 : }
    3416                 : 
    3417                 : void
    3418               0 : nsGfxScrollFrameInner::ReflowCallbackCanceled()
    3419                 : {
    3420               0 :   mPostedReflowCallback = false;
    3421               0 : }
    3422                 : 
    3423               0 : static void LayoutAndInvalidate(nsBoxLayoutState& aState,
    3424                 :                                 nsIFrame* aBox, const nsRect& aRect,
    3425                 :                                 bool aScrollbarIsBeingHidden)
    3426                 : {
    3427                 :   // When a child box changes shape of position, the parent
    3428                 :   // is responsible for invalidation; the overflow rect must be invalidated
    3429                 :   // to make sure to catch any overflow.
    3430                 :   // We invalidate the parent (i.e. the scrollframe) directly, because
    3431                 :   // invalidates coming from scrollbars are suppressed by nsHTMLScrollFrame when
    3432                 :   // mHasVScrollbar/mHasHScrollbar is false, and this is called after those
    3433                 :   // flags have been set ... if a scrollbar is being hidden, we still need
    3434                 :   // to invalidate the scrollbar area here.
    3435                 :   // But we also need to invalidate the scrollbar itself in case it has
    3436                 :   // its own layer; we need to ensure that layer is updated.
    3437               0 :   bool rectChanged = !aBox->GetRect().IsEqualInterior(aRect);
    3438               0 :   if (rectChanged) {
    3439               0 :     if (aScrollbarIsBeingHidden) {
    3440               0 :       aBox->GetParent()->Invalidate(aBox->GetVisualOverflowRect() +
    3441               0 :                                     aBox->GetPosition());
    3442                 :     } else {
    3443               0 :       aBox->InvalidateFrameSubtree();
    3444                 :     }
    3445                 :   }
    3446               0 :   nsBoxFrame::LayoutChildAt(aState, aBox, aRect);
    3447               0 :   if (rectChanged) {
    3448               0 :     if (aScrollbarIsBeingHidden) {
    3449               0 :       aBox->GetParent()->Invalidate(aBox->GetVisualOverflowRect() +
    3450               0 :                                     aBox->GetPosition());
    3451                 :     } else {
    3452               0 :       aBox->InvalidateFrameSubtree();
    3453                 :     }
    3454                 :   }
    3455               0 : }
    3456                 : 
    3457                 : bool
    3458               0 : nsGfxScrollFrameInner::UpdateOverflow()
    3459                 : {
    3460               0 :   nsIScrollableFrame* sf = do_QueryFrame(mOuter);
    3461               0 :   ScrollbarStyles ss = sf->GetScrollbarStyles();
    3462                 : 
    3463               0 :   if (ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN ||
    3464                 :       ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN ||
    3465               0 :       GetScrollPosition() != nsPoint()) {
    3466                 :     // If there are scrollbars, or we're not at the beginning of the pane,
    3467                 :     // the scroll position may change. In this case, mark the frame as
    3468                 :     // needing reflow.
    3469               0 :     mOuter->PresContext()->PresShell()->FrameNeedsReflow(
    3470               0 :       mOuter, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
    3471                 :   }
    3472                 : 
    3473                 :   // Scroll frames never have overflow area because they always clip their
    3474                 :   // children, so return false.
    3475               0 :   return false;
    3476                 : }
    3477                 : 
    3478                 : void
    3479               0 : nsGfxScrollFrameInner::AdjustScrollbarRectForResizer(
    3480                 :                          nsIFrame* aFrame, nsPresContext* aPresContext,
    3481                 :                          nsRect& aRect, bool aHasResizer, bool aVertical)
    3482                 : {
    3483               0 :   if ((aVertical ? aRect.width : aRect.height) == 0)
    3484               0 :     return;
    3485                 : 
    3486                 :   // if a content resizer is present, use its size. Otherwise, check if the
    3487                 :   // widget has a resizer.
    3488               0 :   nsRect resizerRect;
    3489               0 :   if (aHasResizer) {
    3490               0 :     resizerRect = mResizerBox->GetRect();
    3491                 :   }
    3492                 :   else {
    3493               0 :     nsPoint offset;
    3494               0 :     nsIWidget* widget = aFrame->GetNearestWidget(offset);
    3495               0 :     nsIntRect widgetRect;
    3496               0 :     if (!widget || !widget->ShowsResizeIndicator(&widgetRect))
    3497                 :       return;
    3498                 : 
    3499               0 :     resizerRect = nsRect(aPresContext->DevPixelsToAppUnits(widgetRect.x) - offset.x,
    3500               0 :                          aPresContext->DevPixelsToAppUnits(widgetRect.y) - offset.y,
    3501                 :                          aPresContext->DevPixelsToAppUnits(widgetRect.width),
    3502               0 :                          aPresContext->DevPixelsToAppUnits(widgetRect.height));
    3503                 :   }
    3504                 : 
    3505               0 :   if (!resizerRect.Contains(aRect.BottomRight() - nsPoint(1, 1)))
    3506                 :     return;
    3507                 : 
    3508               0 :   if (aVertical)
    3509               0 :     aRect.height = NS_MAX(0, resizerRect.y - aRect.y);
    3510                 :   else
    3511               0 :     aRect.width = NS_MAX(0, resizerRect.x - aRect.x);
    3512                 : }
    3513                 : 
    3514                 : void
    3515               0 : nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState,
    3516                 :                                         const nsRect& aContentArea,
    3517                 :                                         const nsRect& aOldScrollArea)
    3518                 : {
    3519               0 :   NS_ASSERTION(!mSupppressScrollbarUpdate,
    3520                 :                "This should have been suppressed");
    3521                 : 
    3522               0 :   bool hasResizer = HasResizer();
    3523               0 :   bool scrollbarOnLeft = !IsScrollbarOnRight();
    3524                 : 
    3525                 :   // place the scrollcorner
    3526               0 :   if (mScrollCornerBox || mResizerBox) {
    3527               0 :     NS_PRECONDITION(!mScrollCornerBox || mScrollCornerBox->IsBoxFrame(), "Must be a box frame!");
    3528                 : 
    3529               0 :     nsRect r(0, 0, 0, 0);
    3530               0 :     if (aContentArea.x != mScrollPort.x || scrollbarOnLeft) {
    3531                 :       // scrollbar (if any) on left
    3532               0 :       r.x = aContentArea.x;
    3533               0 :       r.width = mScrollPort.x - aContentArea.x;
    3534               0 :       NS_ASSERTION(r.width >= 0, "Scroll area should be inside client rect");
    3535                 :     } else {
    3536                 :       // scrollbar (if any) on right
    3537               0 :       r.width = aContentArea.XMost() - mScrollPort.XMost();
    3538               0 :       r.x = aContentArea.XMost() - r.width;
    3539               0 :       NS_ASSERTION(r.width >= 0, "Scroll area should be inside client rect");
    3540                 :     }
    3541               0 :     if (aContentArea.y != mScrollPort.y) {
    3542               0 :       NS_ERROR("top scrollbars not supported");
    3543                 :     } else {
    3544                 :       // scrollbar (if any) on bottom
    3545               0 :       r.height = aContentArea.YMost() - mScrollPort.YMost();
    3546               0 :       r.y = aContentArea.YMost() - r.height;
    3547               0 :       NS_ASSERTION(r.height >= 0, "Scroll area should be inside client rect");
    3548                 :     }
    3549                 : 
    3550               0 :     if (mScrollCornerBox) {
    3551               0 :       LayoutAndInvalidate(aState, mScrollCornerBox, r, false);
    3552                 :     }
    3553                 : 
    3554               0 :     if (hasResizer) {
    3555                 :       // if a resizer is present, get its size. Assume a default size of 15 pixels.
    3556               0 :       nsSize resizerSize;
    3557               0 :       nscoord defaultSize = nsPresContext::CSSPixelsToAppUnits(15);
    3558                 :       resizerSize.width =
    3559               0 :         mVScrollbarBox ? mVScrollbarBox->GetMinSize(aState).width : defaultSize;
    3560               0 :       if (resizerSize.width > r.width) {
    3561               0 :         r.width = resizerSize.width;
    3562               0 :         if (aContentArea.x == mScrollPort.x && !scrollbarOnLeft)
    3563               0 :           r.x = aContentArea.XMost() - r.width;
    3564                 :       }
    3565                 : 
    3566                 :       resizerSize.height =
    3567               0 :         mHScrollbarBox ? mHScrollbarBox->GetMinSize(aState).height : defaultSize;
    3568               0 :       if (resizerSize.height > r.height) {
    3569               0 :         r.height = resizerSize.height;
    3570               0 :         if (aContentArea.y == mScrollPort.y)
    3571               0 :           r.y = aContentArea.YMost() - r.height;
    3572                 :       }
    3573                 : 
    3574               0 :       LayoutAndInvalidate(aState, mResizerBox, r, false);
    3575                 :     }
    3576               0 :     else if (mResizerBox) {
    3577                 :       // otherwise lay out the resizer with an empty rectangle
    3578               0 :       LayoutAndInvalidate(aState, mResizerBox, nsRect(), false);
    3579                 :     }
    3580                 :   }
    3581                 : 
    3582               0 :   nsPresContext* presContext = mScrolledFrame->PresContext();
    3583               0 :   if (mVScrollbarBox) {
    3584               0 :     NS_PRECONDITION(mVScrollbarBox->IsBoxFrame(), "Must be a box frame!");
    3585               0 :     nsRect vRect(mScrollPort);
    3586               0 :     vRect.width = aContentArea.width - mScrollPort.width;
    3587               0 :     vRect.x = scrollbarOnLeft ? aContentArea.x : mScrollPort.XMost();
    3588               0 :     nsMargin margin;
    3589               0 :     mVScrollbarBox->GetMargin(margin);
    3590               0 :     vRect.Deflate(margin);
    3591               0 :     AdjustScrollbarRectForResizer(mOuter, presContext, vRect, hasResizer, true);
    3592               0 :     LayoutAndInvalidate(aState, mVScrollbarBox, vRect, !mHasVerticalScrollbar);
    3593                 :   }
    3594                 : 
    3595               0 :   if (mHScrollbarBox) {
    3596               0 :     NS_PRECONDITION(mHScrollbarBox->IsBoxFrame(), "Must be a box frame!");
    3597               0 :     nsRect hRect(mScrollPort);
    3598               0 :     hRect.height = aContentArea.height - mScrollPort.height;
    3599               0 :     hRect.y = true ? mScrollPort.YMost() : aContentArea.y;
    3600               0 :     nsMargin margin;
    3601               0 :     mHScrollbarBox->GetMargin(margin);
    3602               0 :     hRect.Deflate(margin);
    3603               0 :     AdjustScrollbarRectForResizer(mOuter, presContext, hRect, hasResizer, false);
    3604               0 :     LayoutAndInvalidate(aState, mHScrollbarBox, hRect, !mHasHorizontalScrollbar);
    3605                 :   }
    3606                 : 
    3607                 :   // may need to update fixed position children of the viewport,
    3608                 :   // if the client area changed size because of an incremental
    3609                 :   // reflow of a descendant.  (If the outer frame is dirty, the fixed
    3610                 :   // children will be re-laid out anyway)
    3611               0 :   if (aOldScrollArea.Size() != mScrollPort.Size() && 
    3612               0 :       !(mOuter->GetStateBits() & NS_FRAME_IS_DIRTY) &&
    3613                 :       mIsRoot) {
    3614               0 :     mMayHaveDirtyFixedChildren = true;
    3615                 :   }
    3616                 :   
    3617                 :   // post reflow callback to modify scrollbar attributes
    3618               0 :   mUpdateScrollbarAttributes = true;
    3619               0 :   if (!mPostedReflowCallback) {
    3620               0 :     aState.PresContext()->PresShell()->PostReflowCallback(this);
    3621               0 :     mPostedReflowCallback = true;
    3622                 :   }
    3623               0 : }
    3624                 : 
    3625                 : void
    3626               0 : nsGfxScrollFrameInner::SetScrollbarEnabled(nsIContent* aContent, nscoord aMaxPos)
    3627                 : {
    3628               0 :   if (aMaxPos) {
    3629               0 :     aContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
    3630                 :   } else {
    3631                 :     aContent->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled,
    3632               0 :                       NS_LITERAL_STRING("true"), true);
    3633                 :   }
    3634               0 : }
    3635                 : 
    3636                 : void
    3637               0 : nsGfxScrollFrameInner::SetCoordAttribute(nsIContent* aContent, nsIAtom* aAtom,
    3638                 :                                          nscoord aSize)
    3639                 : {
    3640                 :   // convert to pixels
    3641               0 :   aSize = nsPresContext::AppUnitsToIntCSSPixels(aSize);
    3642                 : 
    3643                 :   // only set the attribute if it changed.
    3644                 : 
    3645               0 :   nsAutoString newValue;
    3646               0 :   newValue.AppendInt(aSize);
    3647                 : 
    3648               0 :   if (aContent->AttrValueIs(kNameSpaceID_None, aAtom, newValue, eCaseMatters))
    3649                 :     return;
    3650                 : 
    3651               0 :   aContent->SetAttr(kNameSpaceID_None, aAtom, newValue, true);
    3652                 : }
    3653                 : 
    3654                 : static void
    3655               0 : ReduceRadii(nscoord aXBorder, nscoord aYBorder,
    3656                 :             nscoord& aXRadius, nscoord& aYRadius)
    3657                 : {
    3658                 :   // In order to ensure that the inside edge of the border has no
    3659                 :   // curvature, we need at least one of its radii to be zero.
    3660               0 :   if (aXRadius <= aXBorder || aYRadius <= aYBorder)
    3661               0 :     return;
    3662                 : 
    3663                 :   // For any corner where we reduce the radii, preserve the corner's shape.
    3664                 :   double ratio = NS_MAX(double(aXBorder) / aXRadius,
    3665               0 :                         double(aYBorder) / aYRadius);
    3666               0 :   aXRadius *= ratio;
    3667               0 :   aYRadius *= ratio;
    3668                 : }
    3669                 : 
    3670                 : /**
    3671                 :  * Implement an override for nsIFrame::GetBorderRadii to ensure that
    3672                 :  * the clipping region for the border radius does not clip the scrollbars.
    3673                 :  *
    3674                 :  * In other words, we require that the border radius be reduced until the
    3675                 :  * inner border radius at the inner edge of the border is 0 wherever we
    3676                 :  * have scrollbars.
    3677                 :  */
    3678                 : bool
    3679               0 : nsGfxScrollFrameInner::GetBorderRadii(nscoord aRadii[8]) const
    3680                 : {
    3681               0 :   if (!mOuter->nsContainerFrame::GetBorderRadii(aRadii))
    3682               0 :     return false;
    3683                 : 
    3684                 :   // Since we can use GetActualScrollbarSizes (rather than
    3685                 :   // GetDesiredScrollbarSizes) since this doesn't affect reflow, we
    3686                 :   // probably should.
    3687               0 :   nsMargin sb = GetActualScrollbarSizes();
    3688               0 :   nsMargin border = mOuter->GetUsedBorder();
    3689                 : 
    3690               0 :   if (sb.left > 0 || sb.top > 0) {
    3691                 :     ReduceRadii(border.left, border.top,
    3692                 :                 aRadii[NS_CORNER_TOP_LEFT_X],
    3693               0 :                 aRadii[NS_CORNER_TOP_LEFT_Y]);
    3694                 :   }
    3695                 : 
    3696               0 :   if (sb.top > 0 || sb.right > 0) {
    3697                 :     ReduceRadii(border.right, border.top,
    3698               0 :                 aRadii[NS_CORNER_TOP_RIGHT_X],
    3699               0 :                 aRadii[NS_CORNER_TOP_RIGHT_Y]);
    3700                 :   }
    3701                 : 
    3702               0 :   if (sb.right > 0 || sb.bottom > 0) {
    3703                 :     ReduceRadii(border.right, border.bottom,
    3704               0 :                 aRadii[NS_CORNER_BOTTOM_RIGHT_X],
    3705               0 :                 aRadii[NS_CORNER_BOTTOM_RIGHT_Y]);
    3706                 :   }
    3707                 : 
    3708               0 :   if (sb.bottom > 0 || sb.left > 0) {
    3709                 :     ReduceRadii(border.left, border.bottom,
    3710               0 :                 aRadii[NS_CORNER_BOTTOM_LEFT_X],
    3711               0 :                 aRadii[NS_CORNER_BOTTOM_LEFT_Y]);
    3712                 :   }
    3713                 : 
    3714               0 :   return true;
    3715                 : }
    3716                 : 
    3717                 : nsRect
    3718               0 : nsGfxScrollFrameInner::GetScrolledRect() const
    3719                 : {
    3720                 :   nsRect result =
    3721               0 :     GetScrolledRectInternal(mScrolledFrame->GetScrollableOverflowRect(),
    3722               0 :                             mScrollPort.Size());
    3723                 : 
    3724               0 :   NS_ASSERTION(result.width >= mScrollPort.width,
    3725                 :                "Scrolled rect smaller than scrollport?");
    3726               0 :   NS_ASSERTION(result.height >= mScrollPort.height,
    3727                 :                "Scrolled rect smaller than scrollport?");
    3728                 :   return result;
    3729                 : }
    3730                 : 
    3731                 : nsRect
    3732               0 : nsGfxScrollFrameInner::GetScrolledRectInternal(const nsRect& aScrolledFrameOverflowArea,
    3733                 :                                                const nsSize& aScrollPortSize) const
    3734                 : {
    3735               0 :   nscoord x1 = aScrolledFrameOverflowArea.x,
    3736               0 :           x2 = aScrolledFrameOverflowArea.XMost(),
    3737               0 :           y1 = aScrolledFrameOverflowArea.y,
    3738               0 :           y2 = aScrolledFrameOverflowArea.YMost();
    3739               0 :   if (y1 < 0)
    3740               0 :     y1 = 0;
    3741               0 :   if (IsLTR()) {
    3742               0 :     if (x1 < 0)
    3743               0 :       x1 = 0;
    3744                 :   } else {
    3745               0 :     if (x2 > aScrollPortSize.width)
    3746               0 :       x2 = aScrollPortSize.width;
    3747                 :     // When the scrolled frame chooses a size larger than its available width (because
    3748                 :     // its padding alone is larger than the available width), we need to keep the
    3749                 :     // start-edge of the scroll frame anchored to the start-edge of the scrollport. 
    3750                 :     // When the scrolled frame is RTL, this means moving it in our left-based
    3751                 :     // coordinate system, so we need to compensate for its extra width here by
    3752                 :     // effectively repositioning the frame.
    3753               0 :     nscoord extraWidth = NS_MAX(0, mScrolledFrame->GetSize().width - aScrollPortSize.width);
    3754               0 :     x2 += extraWidth;
    3755                 :   }
    3756               0 :   return nsRect(x1, y1, x2 - x1, y2 - y1);
    3757                 : }
    3758                 : 
    3759                 : nsMargin
    3760               0 : nsGfxScrollFrameInner::GetActualScrollbarSizes() const
    3761                 : {
    3762               0 :   nsRect r = mOuter->GetPaddingRect() - mOuter->GetPosition();
    3763                 : 
    3764                 :   return nsMargin(mScrollPort.x - r.x, mScrollPort.y - r.y,
    3765               0 :                   r.XMost() - mScrollPort.XMost(),
    3766               0 :                   r.YMost() - mScrollPort.YMost());
    3767                 : }
    3768                 : 
    3769                 : void
    3770               0 : nsGfxScrollFrameInner::SetScrollbarVisibility(nsIBox* aScrollbar, bool aVisible)
    3771                 : {
    3772               0 :   nsScrollbarFrame* scrollbar = do_QueryFrame(aScrollbar);
    3773               0 :   if (scrollbar) {
    3774                 :     // See if we have a mediator.
    3775               0 :     nsIScrollbarMediator* mediator = scrollbar->GetScrollbarMediator();
    3776               0 :     if (mediator) {
    3777                 :       // Inform the mediator of the visibility change.
    3778               0 :       mediator->VisibilityChanged(aVisible);
    3779                 :     }
    3780                 :   }
    3781               0 : }
    3782                 : 
    3783                 : PRInt32
    3784               0 : nsGfxScrollFrameInner::GetCoordAttribute(nsIBox* aBox, nsIAtom* atom, PRInt32 defaultValue)
    3785                 : {
    3786               0 :   if (aBox) {
    3787               0 :     nsIContent* content = aBox->GetContent();
    3788                 : 
    3789               0 :     nsAutoString value;
    3790               0 :     content->GetAttr(kNameSpaceID_None, atom, value);
    3791               0 :     if (!value.IsEmpty())
    3792                 :     {
    3793                 :       PRInt32 error;
    3794                 : 
    3795                 :       // convert it to an integer
    3796               0 :       defaultValue = nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
    3797                 :     }
    3798                 :   }
    3799                 : 
    3800               0 :   return defaultValue;
    3801                 : }
    3802                 : 
    3803                 : nsPresState*
    3804               0 : nsGfxScrollFrameInner::SaveState(nsIStatefulFrame::SpecialStateID aStateID)
    3805                 : {
    3806                 :   // Don't save "normal" state for the root scrollframe; that's
    3807                 :   // handled via the eDocumentScrollState state id
    3808               0 :   if (mIsRoot && aStateID == nsIStatefulFrame::eNoID) {
    3809               0 :     return nsnull;
    3810                 :   }
    3811                 : 
    3812               0 :   nsIScrollbarMediator* mediator = do_QueryFrame(GetScrolledFrame());
    3813               0 :   if (mediator) {
    3814                 :     // child handles its own scroll state, so don't bother saving state here
    3815               0 :     return nsnull;
    3816                 :   }
    3817                 : 
    3818               0 :   nsPoint scrollPos = GetLogicalScrollPosition();
    3819                 :   // Don't save scroll position if we are at (0,0)
    3820               0 :   if (scrollPos == nsPoint(0,0)) {
    3821               0 :     return nsnull;
    3822                 :   }
    3823                 : 
    3824               0 :   nsPresState* state = new nsPresState();
    3825                 : 
    3826               0 :   state->SetScrollState(scrollPos);
    3827                 : 
    3828               0 :   return state;
    3829                 : }
    3830                 : 
    3831                 : void
    3832               0 : nsGfxScrollFrameInner::RestoreState(nsPresState* aState)
    3833                 : {
    3834               0 :   mRestorePos = aState->GetScrollState();
    3835               0 :   mLastPos.x = -1;
    3836               0 :   mLastPos.y = -1;
    3837               0 :   mDidHistoryRestore = true;
    3838               0 :   mLastPos = mScrolledFrame ? GetLogicalScrollPosition() : nsPoint(0,0);
    3839               0 : }
    3840                 : 
    3841                 : void
    3842               0 : nsGfxScrollFrameInner::PostScrolledAreaEvent()
    3843                 : {
    3844               0 :   if (mScrolledAreaEvent.IsPending()) {
    3845               0 :     return;
    3846                 :   }
    3847               0 :   mScrolledAreaEvent = new ScrolledAreaEvent(this);
    3848               0 :   nsContentUtils::AddScriptRunner(mScrolledAreaEvent.get());
    3849                 : }
    3850                 : 
    3851                 : ////////////////////////////////////////////////////////////////////////////////
    3852                 : // ScrolledArea change event dispatch
    3853                 : 
    3854                 : NS_IMETHODIMP
    3855               0 : nsGfxScrollFrameInner::ScrolledAreaEvent::Run()
    3856                 : {
    3857               0 :   if (mInner) {
    3858               0 :     mInner->FireScrolledAreaEvent();
    3859                 :   }
    3860               0 :   return NS_OK;
    3861                 : }
    3862                 : 
    3863                 : void
    3864               0 : nsGfxScrollFrameInner::FireScrolledAreaEvent()
    3865                 : {
    3866               0 :   mScrolledAreaEvent.Forget();
    3867                 : 
    3868               0 :   nsScrollAreaEvent event(true, NS_SCROLLEDAREACHANGED, nsnull);
    3869               0 :   nsPresContext *prescontext = mOuter->PresContext();
    3870               0 :   nsIContent* content = mOuter->GetContent();
    3871                 : 
    3872               0 :   event.mArea = mScrolledFrame->GetScrollableOverflowRectRelativeToParent();
    3873                 : 
    3874               0 :   nsIDocument *doc = content->GetCurrentDoc();
    3875               0 :   if (doc) {
    3876               0 :     nsEventDispatcher::Dispatch(doc, prescontext, &event, nsnull);
    3877                 :   }
    3878               0 : }

Generated by: LCOV version 1.7