LCOV - code coverage report
Current view: directory - layout/xul/base/src/tree/src - nsTreeBodyFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 2246 0 0.0 %
Date: 2012-06-02 Functions: 127 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 Communicator client 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                 :  *   Dave Hyatt <hyatt@mozilla.org> (Original Author)
      24                 :  *   Ben Goodger <ben@netscape.com>
      25                 :  *   Joe Hewitt <hewitt@netscape.com>
      26                 :  *   Jan Varga <varga@ku.sk>
      27                 :  *   Dean Tessman <dean_tessman@hotmail.com>
      28                 :  *   Brian Ryner <bryner@brianryner.com>
      29                 :  *   Blake Ross <blaker@netscape.com>
      30                 :  *   Pierre Chanial <pierrechanial@netscape.net>
      31                 :  *   Rene Pronk <r.pronk@its.tudelft.nl>
      32                 :  *   Nate Nielsen <nielsen@memberwebs.com>
      33                 :  *   Mark Banner <mark@standard8.demon.co.uk>
      34                 :  *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
      35                 :  *
      36                 :  * Alternatively, the contents of this file may be used under the terms of
      37                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      38                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      39                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      40                 :  * of those above. If you wish to allow use of your version of this file only
      41                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      42                 :  * use your version of this file under the terms of the MPL, indicate your
      43                 :  * decision by deleting the provisions above and replace them with the notice
      44                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      45                 :  * the provisions above, a recipient may use your version of this file under
      46                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      47                 :  *
      48                 :  * ***** END LICENSE BLOCK ***** */
      49                 : 
      50                 : #include "nsCOMPtr.h"
      51                 : #include "nsISupportsArray.h"
      52                 : #include "nsPresContext.h"
      53                 : #include "nsINameSpaceManager.h"
      54                 : 
      55                 : #include "nsTreeBodyFrame.h"
      56                 : #include "nsTreeSelection.h"
      57                 : #include "nsTreeImageListener.h"
      58                 : 
      59                 : #include "nsGkAtoms.h"
      60                 : #include "nsCSSAnonBoxes.h"
      61                 : 
      62                 : #include "nsIContent.h"
      63                 : #include "nsStyleContext.h"
      64                 : #include "nsIBoxObject.h"
      65                 : #include "nsGUIEvent.h"
      66                 : #include "nsAsyncDOMEvent.h"
      67                 : #include "nsIDOMDataContainerEvent.h"
      68                 : #include "nsIDOMMouseEvent.h"
      69                 : #include "nsIPrivateDOMEvent.h"
      70                 : #include "nsIDOMElement.h"
      71                 : #include "nsIDOMNodeList.h"
      72                 : #include "nsIDOMDocument.h"
      73                 : #include "nsIDOMXULElement.h"
      74                 : #include "nsIDocument.h"
      75                 : #include "mozilla/css/StyleRule.h"
      76                 : #include "nsCSSRendering.h"
      77                 : #include "nsIXULTemplateBuilder.h"
      78                 : #include "nsXPIDLString.h"
      79                 : #include "nsContainerFrame.h"
      80                 : #include "nsIView.h"
      81                 : #include "nsIViewManager.h"
      82                 : #include "nsWidgetsCID.h"
      83                 : #include "nsBoxFrame.h"
      84                 : #include "nsBoxObject.h"
      85                 : #include "nsIURL.h"
      86                 : #include "nsNetUtil.h"
      87                 : #include "nsBoxLayoutState.h"
      88                 : #include "nsTreeContentView.h"
      89                 : #include "nsTreeUtils.h"
      90                 : #include "nsChildIterator.h"
      91                 : #include "nsITheme.h"
      92                 : #include "imgIRequest.h"
      93                 : #include "imgIContainer.h"
      94                 : #include "imgIContainerObserver.h"
      95                 : #include "imgILoader.h"
      96                 : #include "nsINodeInfo.h"
      97                 : #include "nsContentUtils.h"
      98                 : #include "nsLayoutUtils.h"
      99                 : #include "nsIScrollableFrame.h"
     100                 : #include "nsEventDispatcher.h"
     101                 : #include "nsDisplayList.h"
     102                 : #include "nsTreeBoxObject.h"
     103                 : #include "nsRenderingContext.h"
     104                 : #include "nsIScriptableRegion.h"
     105                 : 
     106                 : #ifdef IBMBIDI
     107                 : #include "nsBidiUtils.h"
     108                 : #endif
     109                 : 
     110                 : using namespace mozilla;
     111                 : 
     112                 : // Enumeration function that cancels all the image requests in our cache
     113                 : static PLDHashOperator
     114               0 : CancelImageRequest(const nsAString& aKey,
     115                 :                    nsTreeImageCacheEntry aEntry, void* aData)
     116                 : {
     117                 : 
     118                 :   // If our imgIRequest object was registered with the refresh driver,
     119                 :   // then we need to deregister it.
     120               0 :   nsTreeBodyFrame* frame = static_cast<nsTreeBodyFrame*>(aData);
     121                 : 
     122                 :   nsLayoutUtils::DeregisterImageRequest(frame->PresContext(), aEntry.request,
     123               0 :                                         nsnull);
     124                 : 
     125               0 :   aEntry.request->CancelAndForgetObserver(NS_BINDING_ABORTED);
     126               0 :   return PL_DHASH_NEXT;
     127                 : }
     128                 : 
     129                 : //
     130                 : // NS_NewTreeFrame
     131                 : //
     132                 : // Creates a new tree frame
     133                 : //
     134                 : nsIFrame*
     135               0 : NS_NewTreeBodyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     136                 : {
     137               0 :   return new (aPresShell) nsTreeBodyFrame(aPresShell, aContext);
     138                 : }
     139                 : 
     140               0 : NS_IMPL_FRAMEARENA_HELPERS(nsTreeBodyFrame)
     141                 : 
     142               0 : NS_QUERYFRAME_HEAD(nsTreeBodyFrame)
     143               0 :   NS_QUERYFRAME_ENTRY(nsIScrollbarMediator)
     144               0 :   NS_QUERYFRAME_ENTRY(nsTreeBodyFrame)
     145               0 : NS_QUERYFRAME_TAIL_INHERITING(nsLeafBoxFrame)
     146                 : 
     147                 : // Constructor
     148               0 : nsTreeBodyFrame::nsTreeBodyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     149                 : :nsLeafBoxFrame(aPresShell, aContext),
     150                 :  mSlots(nsnull),
     151                 :  mTopRowIndex(0),
     152                 :  mPageLength(0),
     153                 :  mHorzPosition(0),
     154                 :  mHorzWidth(0),
     155                 :  mAdjustWidth(0),
     156                 :  mRowHeight(0),
     157                 :  mIndentation(0),
     158                 :  mStringWidth(-1),
     159                 :  mUpdateBatchNest(0),
     160                 :  mRowCount(0),
     161                 :  mMouseOverRow(-1),
     162                 :  mFocused(false),
     163                 :  mHasFixedRowCount(false),
     164                 :  mVerticalOverflow(false),
     165                 :  mHorizontalOverflow(false),
     166               0 :  mReflowCallbackPosted(false)
     167                 : {
     168               0 :   mColumns = new nsTreeColumns(nsnull);
     169               0 :   NS_NewISupportsArray(getter_AddRefs(mScratchArray));
     170               0 : }
     171                 : 
     172                 : // Destructor
     173               0 : nsTreeBodyFrame::~nsTreeBodyFrame()
     174                 : {
     175               0 :   mImageCache.EnumerateRead(CancelImageRequest, this);
     176               0 :   DetachImageListeners();
     177               0 :   delete mSlots;
     178               0 : }
     179                 : 
     180                 : static void
     181               0 : GetBorderPadding(nsStyleContext* aContext, nsMargin& aMargin)
     182                 : {
     183               0 :   aMargin.SizeTo(0, 0, 0, 0);
     184               0 :   if (!aContext->GetStylePadding()->GetPadding(aMargin)) {
     185               0 :     NS_NOTYETIMPLEMENTED("percentage padding");
     186                 :   }
     187               0 :   aMargin += aContext->GetStyleBorder()->GetActualBorder();
     188               0 : }
     189                 : 
     190                 : static void
     191               0 : AdjustForBorderPadding(nsStyleContext* aContext, nsRect& aRect)
     192                 : {
     193               0 :   nsMargin borderPadding(0, 0, 0, 0);
     194               0 :   GetBorderPadding(aContext, borderPadding);
     195               0 :   aRect.Deflate(borderPadding);
     196               0 : }
     197                 : 
     198                 : NS_IMETHODIMP
     199               0 : nsTreeBodyFrame::Init(nsIContent*     aContent,
     200                 :                       nsIFrame*       aParent,
     201                 :                       nsIFrame*       aPrevInFlow)
     202                 : {
     203               0 :   nsresult rv = nsLeafBoxFrame::Init(aContent, aParent, aPrevInFlow);
     204               0 :   NS_ENSURE_SUCCESS(rv, rv);
     205                 : 
     206               0 :   mIndentation = GetIndentation();
     207               0 :   mRowHeight = GetRowHeight();
     208                 : 
     209               0 :   NS_ENSURE_TRUE(mCreatedListeners.Init(), NS_ERROR_OUT_OF_MEMORY);
     210                 : 
     211               0 :   NS_ENSURE_TRUE(mImageCache.Init(16), NS_ERROR_OUT_OF_MEMORY);
     212               0 :   EnsureBoxObject();
     213                 : 
     214               0 :   return rv;
     215                 : }
     216                 : 
     217                 : nsSize
     218               0 : nsTreeBodyFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
     219                 : {
     220               0 :   EnsureView();
     221                 : 
     222               0 :   nsIContent* baseElement = GetBaseElement();
     223                 : 
     224               0 :   nsSize min(0,0);
     225                 :   PRInt32 desiredRows;
     226               0 :   if (NS_UNLIKELY(!baseElement)) {
     227               0 :     desiredRows = 0;
     228                 :   }
     229               0 :   else if (baseElement->Tag() == nsGkAtoms::select &&
     230               0 :            baseElement->IsHTML()) {
     231               0 :     min.width = CalcMaxRowWidth();
     232               0 :     nsAutoString size;
     233               0 :     baseElement->GetAttr(kNameSpaceID_None, nsGkAtoms::size, size);
     234               0 :     if (!size.IsEmpty()) {
     235                 :       PRInt32 err;
     236               0 :       desiredRows = size.ToInteger(&err);
     237               0 :       mHasFixedRowCount = true;
     238               0 :       mPageLength = desiredRows;
     239                 :     }
     240                 :     else {
     241               0 :       desiredRows = 1;
     242                 :     }
     243                 :   }
     244                 :   else {
     245                 :     // tree
     246               0 :     nsAutoString rows;
     247               0 :     baseElement->GetAttr(kNameSpaceID_None, nsGkAtoms::rows, rows);
     248               0 :     if (!rows.IsEmpty()) {
     249                 :       PRInt32 err;
     250               0 :       desiredRows = rows.ToInteger(&err);
     251               0 :       mPageLength = desiredRows;
     252                 :     }
     253                 :     else {
     254               0 :       desiredRows = 0;
     255                 :     }
     256                 :   }
     257                 : 
     258               0 :   min.height = mRowHeight * desiredRows;
     259                 : 
     260               0 :   AddBorderAndPadding(min);
     261                 :   bool widthSet, heightSet;
     262               0 :   nsIBox::AddCSSMinSize(aBoxLayoutState, this, min, widthSet, heightSet);
     263                 : 
     264                 :   return min;
     265                 : }
     266                 : 
     267                 : nscoord
     268               0 : nsTreeBodyFrame::CalcMaxRowWidth()
     269                 : {
     270               0 :   if (mStringWidth != -1)
     271               0 :     return mStringWidth;
     272                 : 
     273               0 :   if (!mView)
     274               0 :     return 0;
     275                 : 
     276               0 :   nsStyleContext* rowContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreerow);
     277               0 :   nsMargin rowMargin(0,0,0,0);
     278               0 :   GetBorderPadding(rowContext, rowMargin);
     279                 : 
     280                 :   nscoord rowWidth;
     281                 :   nsTreeColumn* col;
     282                 : 
     283                 :   nsRefPtr<nsRenderingContext> rc =
     284               0 :     PresContext()->PresShell()->GetReferenceRenderingContext();
     285               0 :   if (!rc)
     286               0 :     return 0;
     287                 : 
     288               0 :   for (PRInt32 row = 0; row < mRowCount; ++row) {
     289               0 :     rowWidth = 0;
     290                 : 
     291               0 :     for (col = mColumns->GetFirstColumn(); col; col = col->GetNext()) {
     292                 :       nscoord desiredWidth, currentWidth;
     293               0 :       nsresult rv = GetCellWidth(row, col, rc, desiredWidth, currentWidth);
     294               0 :       if (NS_FAILED(rv)) {
     295               0 :         NS_NOTREACHED("invalid column");
     296               0 :         continue;
     297                 :       }
     298               0 :       rowWidth += desiredWidth;
     299                 :     }
     300                 : 
     301               0 :     if (rowWidth > mStringWidth)
     302               0 :       mStringWidth = rowWidth;
     303                 :   }
     304                 : 
     305               0 :   mStringWidth += rowMargin.left + rowMargin.right;
     306               0 :   return mStringWidth;
     307                 : }
     308                 : 
     309                 : void
     310               0 : nsTreeBodyFrame::DestroyFrom(nsIFrame* aDestructRoot)
     311                 : {
     312               0 :   mScrollEvent.Revoke();
     313                 :   // Make sure we cancel any posted callbacks. 
     314               0 :   if (mReflowCallbackPosted) {
     315               0 :     PresContext()->PresShell()->CancelReflowCallback(this);
     316               0 :     mReflowCallbackPosted = false;
     317                 :   }
     318                 : 
     319               0 :   if (mColumns)
     320               0 :     mColumns->SetTree(nsnull);
     321                 : 
     322                 :   // Save off our info into the box object.
     323               0 :   nsCOMPtr<nsPIBoxObject> box(do_QueryInterface(mTreeBoxObject));
     324               0 :   if (box) {
     325               0 :     if (mTopRowIndex > 0) {
     326               0 :       nsAutoString topRowStr; topRowStr.AssignLiteral("topRow");
     327               0 :       nsAutoString topRow;
     328               0 :       topRow.AppendInt(mTopRowIndex);
     329               0 :       box->SetProperty(topRowStr.get(), topRow.get());
     330                 :     }
     331                 : 
     332                 :     // Always null out the cached tree body frame.
     333               0 :     box->ClearCachedValues();
     334                 : 
     335               0 :     mTreeBoxObject = nsnull; // Drop our ref here.
     336                 :   }
     337                 : 
     338               0 :   if (mView) {
     339               0 :     nsCOMPtr<nsITreeSelection> sel;
     340               0 :     mView->GetSelection(getter_AddRefs(sel));
     341               0 :     if (sel)
     342               0 :       sel->SetTree(nsnull);
     343               0 :     mView->SetTree(nsnull);
     344               0 :     mView = nsnull;
     345                 :   }
     346                 : 
     347               0 :   nsLeafBoxFrame::DestroyFrom(aDestructRoot);
     348               0 : }
     349                 : 
     350                 : void
     351               0 : nsTreeBodyFrame::EnsureBoxObject()
     352                 : {
     353               0 :   if (!mTreeBoxObject) {
     354               0 :     nsIContent* parent = GetBaseElement();
     355               0 :     if (parent) {
     356               0 :       nsIDocument* nsDoc = parent->GetDocument();
     357               0 :       if (!nsDoc) // there may be no document, if we're called from Destroy()
     358               0 :         return;
     359               0 :       nsCOMPtr<nsIBoxObject> box;
     360               0 :       nsCOMPtr<nsIDOMElement> domElem = do_QueryInterface(parent);
     361               0 :       nsDoc->GetBoxObjectFor(domElem, getter_AddRefs(box));
     362                 :       // Ensure that we got a native box object.
     363               0 :       nsCOMPtr<nsPIBoxObject> pBox = do_QueryInterface(box);
     364               0 :       if (pBox) {
     365               0 :         nsCOMPtr<nsITreeBoxObject> realTreeBoxObject = do_QueryInterface(pBox);
     366               0 :         if (realTreeBoxObject) {
     367                 :           nsTreeBodyFrame* innerTreeBoxObject =
     368               0 :             static_cast<nsTreeBoxObject*>(realTreeBoxObject.get())
     369               0 :               ->GetCachedTreeBody();
     370               0 :           ENSURE_TRUE(!innerTreeBoxObject || innerTreeBoxObject == this);
     371               0 :           mTreeBoxObject = realTreeBoxObject;
     372               0 :           mColumns->SetTree(mTreeBoxObject);
     373                 :         }
     374                 :       }
     375                 :     }
     376                 :   }
     377                 : }
     378                 : 
     379                 : void
     380               0 : nsTreeBodyFrame::EnsureView()
     381                 : {
     382               0 :   if (!mView) {
     383               0 :     if (PresContext()->PresShell()->IsReflowLocked()) {
     384               0 :       if (!mReflowCallbackPosted) {
     385               0 :         mReflowCallbackPosted = true;
     386               0 :         PresContext()->PresShell()->PostReflowCallback(this);
     387                 :       }
     388               0 :       return;
     389                 :     }
     390               0 :     nsCOMPtr<nsIBoxObject> box = do_QueryInterface(mTreeBoxObject);
     391               0 :     if (box) {
     392               0 :       nsWeakFrame weakFrame(this);
     393               0 :       nsCOMPtr<nsITreeView> treeView;
     394               0 :       mTreeBoxObject->GetView(getter_AddRefs(treeView));
     395               0 :       if (treeView && weakFrame.IsAlive()) {
     396               0 :         nsXPIDLString rowStr;
     397               0 :         box->GetProperty(NS_LITERAL_STRING("topRow").get(),
     398               0 :                          getter_Copies(rowStr));
     399               0 :         nsAutoString rowStr2(rowStr);
     400                 :         PRInt32 error;
     401               0 :         PRInt32 rowIndex = rowStr2.ToInteger(&error);
     402                 : 
     403                 :         // Set our view.
     404               0 :         SetView(treeView);
     405               0 :         ENSURE_TRUE(weakFrame.IsAlive());
     406                 : 
     407                 :         // Scroll to the given row.
     408                 :         // XXX is this optimal if we haven't laid out yet?
     409               0 :         ScrollToRow(rowIndex);
     410                 : 
     411                 :         // Clear out the property info for the top row, but we always keep the
     412                 :         // view current.
     413               0 :         box->RemoveProperty(NS_LITERAL_STRING("topRow").get());
     414                 :       }
     415                 :     }
     416                 :   }
     417                 : }
     418                 : 
     419                 : void
     420               0 : nsTreeBodyFrame::SetBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect,
     421                 :                            bool aRemoveOverflowArea)
     422                 : {
     423               0 :   nscoord horzWidth = CalcHorzWidth(GetScrollParts());
     424               0 :   if ((!aRect.IsEqualEdges(mRect) || mHorzWidth != horzWidth) && !mReflowCallbackPosted) {
     425               0 :     mReflowCallbackPosted = true;
     426               0 :     PresContext()->PresShell()->PostReflowCallback(this);
     427                 :   }
     428                 : 
     429               0 :   mHorzWidth = horzWidth;
     430                 : 
     431               0 :   nsLeafBoxFrame::SetBounds(aBoxLayoutState, aRect, aRemoveOverflowArea);
     432               0 : }
     433                 : 
     434                 : 
     435                 : bool
     436               0 : nsTreeBodyFrame::ReflowFinished()
     437                 : {
     438               0 :   if (!mView) {
     439               0 :     nsWeakFrame weakFrame(this);
     440               0 :     EnsureView();
     441               0 :     NS_ENSURE_TRUE(weakFrame.IsAlive(), false);
     442                 :   }
     443               0 :   if (mView) {
     444               0 :     CalcInnerBox();
     445               0 :     ScrollParts parts = GetScrollParts();
     446               0 :     mHorzWidth = CalcHorzWidth(parts);
     447               0 :     if (!mHasFixedRowCount) {
     448               0 :       mPageLength = mInnerBox.height / mRowHeight;
     449                 :     }
     450                 : 
     451               0 :     PRInt32 lastPageTopRow = NS_MAX(0, mRowCount - mPageLength);
     452               0 :     if (mTopRowIndex > lastPageTopRow)
     453               0 :       ScrollToRowInternal(parts, lastPageTopRow);
     454                 : 
     455               0 :     nsIContent *treeContent = GetBaseElement();
     456               0 :     if (treeContent &&
     457                 :         treeContent->AttrValueIs(kNameSpaceID_None,
     458                 :                                  nsGkAtoms::keepcurrentinview,
     459               0 :                                  nsGkAtoms::_true, eCaseMatters)) {
     460                 :       // make sure that the current selected item is still
     461                 :       // visible after the tree changes size.
     462               0 :       nsCOMPtr<nsITreeSelection> sel;
     463               0 :       mView->GetSelection(getter_AddRefs(sel));
     464               0 :       if (sel) {
     465                 :         PRInt32 currentIndex;
     466               0 :         sel->GetCurrentIndex(&currentIndex);
     467               0 :         if (currentIndex != -1)
     468               0 :           EnsureRowIsVisibleInternal(parts, currentIndex);
     469                 :       }
     470                 :     }
     471                 : 
     472               0 :     if (!FullScrollbarsUpdate(false)) {
     473               0 :       return false;
     474                 :     }
     475                 :   }
     476                 : 
     477               0 :   mReflowCallbackPosted = false;
     478               0 :   return false;
     479                 : }
     480                 : 
     481                 : void
     482               0 : nsTreeBodyFrame::ReflowCallbackCanceled()
     483                 : {
     484               0 :   mReflowCallbackPosted = false;
     485               0 : }
     486                 : 
     487                 : nsresult
     488               0 : nsTreeBodyFrame::GetView(nsITreeView * *aView)
     489                 : {
     490               0 :   *aView = nsnull;
     491               0 :   nsWeakFrame weakFrame(this);
     492               0 :   EnsureView();
     493               0 :   NS_ENSURE_STATE(weakFrame.IsAlive());
     494               0 :   NS_IF_ADDREF(*aView = mView);
     495               0 :   return NS_OK;
     496                 : }
     497                 : 
     498                 : nsresult
     499               0 : nsTreeBodyFrame::SetView(nsITreeView * aView)
     500                 : {
     501                 :   // First clear out the old view.
     502               0 :   if (mView) {
     503               0 :     nsCOMPtr<nsITreeSelection> sel;
     504               0 :     mView->GetSelection(getter_AddRefs(sel));
     505               0 :     if (sel)
     506               0 :       sel->SetTree(nsnull);
     507               0 :     mView->SetTree(nsnull);
     508                 : 
     509                 :     // Only reset the top row index and delete the columns if we had an old non-null view.
     510               0 :     mTopRowIndex = 0;
     511                 :   }
     512                 : 
     513                 :   // Tree, meet the view.
     514               0 :   mView = aView;
     515                 :  
     516                 :   // Changing the view causes us to refetch our data.  This will
     517                 :   // necessarily entail a full invalidation of the tree.
     518               0 :   Invalidate();
     519                 :  
     520               0 :   nsIContent *treeContent = GetBaseElement();
     521               0 :   if (treeContent) {
     522               0 :     FireDOMEvent(NS_LITERAL_STRING("TreeViewChanged"), treeContent);
     523                 :   }
     524                 : 
     525               0 :   if (mView) {
     526                 :     // Give the view a new empty selection object to play with, but only if it
     527                 :     // doesn't have one already.
     528               0 :     nsCOMPtr<nsITreeSelection> sel;
     529               0 :     mView->GetSelection(getter_AddRefs(sel));
     530               0 :     if (sel) {
     531               0 :       sel->SetTree(mTreeBoxObject);
     532                 :     }
     533                 :     else {
     534               0 :       NS_NewTreeSelection(mTreeBoxObject, getter_AddRefs(sel));
     535               0 :       mView->SetSelection(sel);
     536                 :     }
     537                 : 
     538                 :     // View, meet the tree.
     539               0 :     nsWeakFrame weakFrame(this);
     540               0 :     mView->SetTree(mTreeBoxObject);
     541               0 :     NS_ENSURE_STATE(weakFrame.IsAlive());
     542               0 :     mView->GetRowCount(&mRowCount);
     543                 :  
     544               0 :     if (!PresContext()->PresShell()->IsReflowLocked()) {
     545                 :       // The scrollbar will need to be updated.
     546               0 :       FullScrollbarsUpdate(false);
     547               0 :     } else if (!mReflowCallbackPosted) {
     548               0 :       mReflowCallbackPosted = true;
     549               0 :       PresContext()->PresShell()->PostReflowCallback(this);
     550                 :     }
     551                 :   }
     552                 :  
     553               0 :   return NS_OK;
     554                 : }
     555                 : 
     556                 : nsresult
     557               0 : nsTreeBodyFrame::GetFocused(bool* aFocused)
     558                 : {
     559               0 :   *aFocused = mFocused;
     560               0 :   return NS_OK;
     561                 : }
     562                 : 
     563                 : nsresult
     564               0 : nsTreeBodyFrame::SetFocused(bool aFocused)
     565                 : {
     566               0 :   if (mFocused != aFocused) {
     567               0 :     mFocused = aFocused;
     568               0 :     if (mView) {
     569               0 :       nsCOMPtr<nsITreeSelection> sel;
     570               0 :       mView->GetSelection(getter_AddRefs(sel));
     571               0 :       if (sel)
     572               0 :         sel->InvalidateSelection();
     573                 :     }
     574                 :   }
     575               0 :   return NS_OK;
     576                 : }
     577                 : 
     578                 : nsresult
     579               0 : nsTreeBodyFrame::GetTreeBody(nsIDOMElement** aElement)
     580                 : {
     581                 :   //NS_ASSERTION(mContent, "no content, see bug #104878");
     582               0 :   if (!mContent)
     583               0 :     return NS_ERROR_NULL_POINTER;
     584                 : 
     585               0 :   return mContent->QueryInterface(NS_GET_IID(nsIDOMElement), (void**)aElement);
     586                 : }
     587                 : 
     588                 : nsresult
     589               0 : nsTreeBodyFrame::GetColumns(nsITreeColumns** aColumns)
     590                 : {
     591               0 :   NS_IF_ADDREF(*aColumns = mColumns);
     592               0 :   return NS_OK;
     593                 : }
     594                 : 
     595                 : nsresult
     596               0 : nsTreeBodyFrame::GetRowHeight(PRInt32* _retval)
     597                 : {
     598               0 :   *_retval = nsPresContext::AppUnitsToIntCSSPixels(mRowHeight);
     599               0 :   return NS_OK;
     600                 : }
     601                 : 
     602                 : nsresult
     603               0 : nsTreeBodyFrame::GetRowWidth(PRInt32 *aRowWidth)
     604                 : {
     605               0 :   *aRowWidth = nsPresContext::AppUnitsToIntCSSPixels(CalcHorzWidth(GetScrollParts()));
     606               0 :   return NS_OK;
     607                 : }
     608                 : 
     609                 : nsresult
     610               0 : nsTreeBodyFrame::GetFirstVisibleRow(PRInt32 *_retval)
     611                 : {
     612               0 :   *_retval = mTopRowIndex;
     613               0 :   return NS_OK;
     614                 : }
     615                 : 
     616                 : nsresult
     617               0 : nsTreeBodyFrame::GetLastVisibleRow(PRInt32 *_retval)
     618                 : {
     619               0 :   *_retval = GetLastVisibleRow();
     620               0 :   return NS_OK;
     621                 : }
     622                 : 
     623                 : nsresult
     624               0 : nsTreeBodyFrame::GetHorizontalPosition(PRInt32 *aHorizontalPosition)
     625                 : {
     626               0 :   *aHorizontalPosition = nsPresContext::AppUnitsToIntCSSPixels(mHorzPosition); 
     627               0 :   return NS_OK;
     628                 : }
     629                 : 
     630                 : nsresult
     631               0 : nsTreeBodyFrame::GetPageLength(PRInt32 *_retval)
     632                 : {
     633               0 :   *_retval = mPageLength;
     634               0 :   return NS_OK;
     635                 : }
     636                 : 
     637                 : nsresult
     638               0 : nsTreeBodyFrame::GetSelectionRegion(nsIScriptableRegion **aRegion)
     639                 : {
     640               0 :   *aRegion = nsnull;
     641                 : 
     642               0 :   nsCOMPtr<nsITreeSelection> selection;
     643               0 :   mView->GetSelection(getter_AddRefs(selection));
     644               0 :   NS_ENSURE_TRUE(selection, NS_OK);
     645                 : 
     646               0 :   nsCOMPtr<nsIScriptableRegion> region = do_CreateInstance("@mozilla.org/gfx/region;1");
     647               0 :   NS_ENSURE_TRUE(region, NS_ERROR_FAILURE);
     648               0 :   region->Init();
     649                 : 
     650               0 :   nsRefPtr<nsPresContext> presContext = PresContext();
     651               0 :   nsIntRect rect = mRect.ToOutsidePixels(presContext->AppUnitsPerCSSPixel());
     652                 : 
     653               0 :   nsIFrame* rootFrame = presContext->PresShell()->GetRootFrame();
     654               0 :   nsPoint origin = GetOffsetTo(rootFrame);
     655                 : 
     656                 :   // iterate through the visible rows and add the selected ones to the
     657                 :   // drag region
     658               0 :   PRInt32 x = nsPresContext::AppUnitsToIntCSSPixels(origin.x);
     659               0 :   PRInt32 y = nsPresContext::AppUnitsToIntCSSPixels(origin.y);
     660               0 :   PRInt32 top = y;
     661               0 :   PRInt32 end = GetLastVisibleRow();
     662               0 :   PRInt32 rowHeight = nsPresContext::AppUnitsToIntCSSPixels(mRowHeight);
     663               0 :   for (PRInt32 i = mTopRowIndex; i <= end; i++) {
     664                 :     bool isSelected;
     665               0 :     selection->IsSelected(i, &isSelected);
     666               0 :     if (isSelected)
     667               0 :       region->UnionRect(x, y, rect.width, rowHeight);
     668               0 :     y += rowHeight;
     669                 :   }
     670                 : 
     671                 :   // clip to the tree boundary in case one row extends past it
     672               0 :   region->IntersectRect(x, top, rect.width, rect.height);
     673                 : 
     674               0 :   NS_ADDREF(*aRegion = region);
     675               0 :   return NS_OK;
     676                 : }
     677                 : 
     678                 : nsresult
     679               0 : nsTreeBodyFrame::Invalidate()
     680                 : {
     681               0 :   if (mUpdateBatchNest)
     682               0 :     return NS_OK;
     683                 : 
     684               0 :   InvalidateOverflowRect();
     685                 : 
     686               0 :   return NS_OK;
     687                 : }
     688                 : 
     689                 : nsresult
     690               0 : nsTreeBodyFrame::InvalidateColumn(nsITreeColumn* aCol)
     691                 : {
     692               0 :   if (mUpdateBatchNest)
     693               0 :     return NS_OK;
     694                 : 
     695               0 :   nsRefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
     696               0 :   if (!col)
     697               0 :     return NS_ERROR_INVALID_ARG;
     698                 : 
     699                 : #ifdef ACCESSIBILITY
     700               0 :   if (nsIPresShell::IsAccessibilityActive())
     701               0 :     FireInvalidateEvent(-1, -1, aCol, aCol);
     702                 : #endif
     703                 : 
     704               0 :   nsRect columnRect;
     705               0 :   nsresult rv = col->GetRect(this, mInnerBox.y, mInnerBox.height, &columnRect);
     706               0 :   NS_ENSURE_SUCCESS(rv, rv);
     707                 : 
     708                 :   // When false then column is out of view
     709               0 :   if (OffsetForHorzScroll(columnRect, true))
     710               0 :       nsIFrame::Invalidate(columnRect);
     711                 : 
     712               0 :   return NS_OK;
     713                 : }
     714                 : 
     715                 : nsresult
     716               0 : nsTreeBodyFrame::InvalidateRow(PRInt32 aIndex)
     717                 : {
     718               0 :   if (mUpdateBatchNest)
     719               0 :     return NS_OK;
     720                 : 
     721                 : #ifdef ACCESSIBILITY
     722               0 :   if (nsIPresShell::IsAccessibilityActive())
     723               0 :     FireInvalidateEvent(aIndex, aIndex, nsnull, nsnull);
     724                 : #endif
     725                 : 
     726               0 :   aIndex -= mTopRowIndex;
     727               0 :   if (aIndex < 0 || aIndex > mPageLength)
     728               0 :     return NS_OK;
     729                 : 
     730               0 :   nsRect rowRect(mInnerBox.x, mInnerBox.y+mRowHeight*aIndex, mInnerBox.width, mRowHeight);
     731               0 :   nsLeafBoxFrame::Invalidate(rowRect);
     732                 : 
     733               0 :   return NS_OK;
     734                 : }
     735                 : 
     736                 : nsresult
     737               0 : nsTreeBodyFrame::InvalidateCell(PRInt32 aIndex, nsITreeColumn* aCol)
     738                 : {
     739               0 :   if (mUpdateBatchNest)
     740               0 :     return NS_OK;
     741                 : 
     742                 : #ifdef ACCESSIBILITY
     743               0 :   if (nsIPresShell::IsAccessibilityActive())
     744               0 :     FireInvalidateEvent(aIndex, aIndex, aCol, aCol);
     745                 : #endif
     746                 : 
     747               0 :   aIndex -= mTopRowIndex;
     748               0 :   if (aIndex < 0 || aIndex > mPageLength)
     749               0 :     return NS_OK;
     750                 : 
     751               0 :   nsRefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
     752               0 :   if (!col)
     753               0 :     return NS_ERROR_INVALID_ARG;
     754                 : 
     755               0 :   nsRect cellRect;
     756                 :   nsresult rv = col->GetRect(this, mInnerBox.y+mRowHeight*aIndex, mRowHeight,
     757               0 :                              &cellRect);
     758               0 :   NS_ENSURE_SUCCESS(rv, rv);
     759                 : 
     760               0 :   if (OffsetForHorzScroll(cellRect, true))
     761               0 :     nsIFrame::Invalidate(cellRect);
     762                 : 
     763               0 :   return NS_OK;
     764                 : }
     765                 : 
     766                 : nsresult
     767               0 : nsTreeBodyFrame::InvalidateRange(PRInt32 aStart, PRInt32 aEnd)
     768                 : {
     769               0 :   if (mUpdateBatchNest)
     770               0 :     return NS_OK;
     771                 : 
     772               0 :   if (aStart == aEnd)
     773               0 :     return InvalidateRow(aStart);
     774                 : 
     775               0 :   PRInt32 last = GetLastVisibleRow();
     776               0 :   if (aStart > aEnd || aEnd < mTopRowIndex || aStart > last)
     777               0 :     return NS_OK;
     778                 : 
     779               0 :   if (aStart < mTopRowIndex)
     780               0 :     aStart = mTopRowIndex;
     781                 : 
     782               0 :   if (aEnd > last)
     783               0 :     aEnd = last;
     784                 : 
     785                 : #ifdef ACCESSIBILITY
     786               0 :   if (nsIPresShell::IsAccessibilityActive()) {
     787                 :     PRInt32 end =
     788               0 :       mRowCount > 0 ? ((mRowCount <= aEnd) ? mRowCount - 1 : aEnd) : 0;
     789               0 :     FireInvalidateEvent(aStart, end, nsnull, nsnull);
     790                 :   }
     791                 : #endif
     792                 : 
     793               0 :   nsRect rangeRect(mInnerBox.x, mInnerBox.y+mRowHeight*(aStart-mTopRowIndex), mInnerBox.width, mRowHeight*(aEnd-aStart+1));
     794               0 :   nsIFrame::Invalidate(rangeRect);
     795                 : 
     796               0 :   return NS_OK;
     797                 : }
     798                 : 
     799                 : nsresult
     800               0 : nsTreeBodyFrame::InvalidateColumnRange(PRInt32 aStart, PRInt32 aEnd, nsITreeColumn* aCol)
     801                 : {
     802               0 :   if (mUpdateBatchNest)
     803               0 :     return NS_OK;
     804                 : 
     805               0 :   nsRefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
     806               0 :   if (!col)
     807               0 :     return NS_ERROR_INVALID_ARG;
     808                 : 
     809               0 :   if (aStart == aEnd)
     810               0 :     return InvalidateCell(aStart, col);
     811                 : 
     812               0 :   PRInt32 last = GetLastVisibleRow();
     813               0 :   if (aStart > aEnd || aEnd < mTopRowIndex || aStart > last)
     814               0 :     return NS_OK;
     815                 : 
     816               0 :   if (aStart < mTopRowIndex)
     817               0 :     aStart = mTopRowIndex;
     818                 : 
     819               0 :   if (aEnd > last)
     820               0 :     aEnd = last;
     821                 : 
     822                 : #ifdef ACCESSIBILITY
     823               0 :   if (nsIPresShell::IsAccessibilityActive()) {
     824                 :     PRInt32 end =
     825               0 :       mRowCount > 0 ? ((mRowCount <= aEnd) ? mRowCount - 1 : aEnd) : 0;
     826               0 :     FireInvalidateEvent(aStart, end, aCol, aCol);
     827                 :   }
     828                 : #endif
     829                 : 
     830               0 :   nsRect rangeRect;
     831                 :   nsresult rv = col->GetRect(this, 
     832                 :                              mInnerBox.y+mRowHeight*(aStart-mTopRowIndex),
     833                 :                              mRowHeight*(aEnd-aStart+1),
     834               0 :                              &rangeRect);
     835               0 :   NS_ENSURE_SUCCESS(rv, rv);
     836                 : 
     837               0 :   nsIFrame::Invalidate(rangeRect);
     838                 : 
     839               0 :   return NS_OK;
     840                 : }
     841                 : 
     842                 : static void
     843               0 : FindScrollParts(nsIFrame* aCurrFrame, nsTreeBodyFrame::ScrollParts* aResult)
     844                 : {
     845               0 :   if (!aResult->mColumnsScrollFrame) {
     846               0 :     nsIScrollableFrame* f = do_QueryFrame(aCurrFrame);
     847               0 :     if (f) {
     848               0 :       aResult->mColumnsFrame = aCurrFrame;
     849               0 :       aResult->mColumnsScrollFrame = f;
     850                 :     }
     851                 :   }
     852                 :   
     853               0 :   nsScrollbarFrame *sf = do_QueryFrame(aCurrFrame);
     854               0 :   if (sf) {
     855               0 :     if (!aCurrFrame->IsHorizontal()) {
     856               0 :       if (!aResult->mVScrollbar) {
     857               0 :         aResult->mVScrollbar = sf;
     858                 :       }
     859                 :     } else {
     860               0 :       if (!aResult->mHScrollbar) {
     861               0 :         aResult->mHScrollbar = sf;
     862                 :       }
     863                 :     }
     864                 :     // don't bother searching inside a scrollbar
     865               0 :     return;
     866                 :   }
     867                 :   
     868               0 :   nsIFrame* child = aCurrFrame->GetFirstPrincipalChild();
     869               0 :   while (child &&
     870               0 :          !child->GetContent()->IsRootOfNativeAnonymousSubtree() &&
     871               0 :          (!aResult->mVScrollbar || !aResult->mHScrollbar ||
     872               0 :           !aResult->mColumnsScrollFrame)) {
     873               0 :     FindScrollParts(child, aResult);
     874               0 :     child = child->GetNextSibling();
     875                 :   }
     876                 : }
     877                 : 
     878               0 : nsTreeBodyFrame::ScrollParts nsTreeBodyFrame::GetScrollParts()
     879                 : {
     880               0 :   ScrollParts result = { nsnull, nsnull, nsnull, nsnull, nsnull, nsnull };
     881               0 :   nsIContent* baseElement = GetBaseElement();
     882                 :   nsIFrame* treeFrame =
     883               0 :     baseElement ? baseElement->GetPrimaryFrame() : nsnull;
     884               0 :   if (treeFrame) {
     885                 :     // The way we do this, searching through the entire frame subtree, is pretty
     886                 :     // dumb! We should know where these frames are.
     887               0 :     FindScrollParts(treeFrame, &result);
     888               0 :     if (result.mHScrollbar) {
     889               0 :       result.mHScrollbar->SetScrollbarMediatorContent(GetContent());
     890               0 :       nsIFrame* f = do_QueryFrame(result.mHScrollbar);
     891               0 :       result.mHScrollbarContent = f->GetContent();
     892                 :     }
     893               0 :     if (result.mVScrollbar) {
     894               0 :       result.mVScrollbar->SetScrollbarMediatorContent(GetContent());
     895               0 :       nsIFrame* f = do_QueryFrame(result.mVScrollbar);
     896               0 :       result.mVScrollbarContent = f->GetContent();
     897                 :     }
     898                 :   }
     899                 :   return result;
     900                 : }
     901                 : 
     902                 : void
     903               0 : nsTreeBodyFrame::UpdateScrollbars(const ScrollParts& aParts)
     904                 : {
     905               0 :   nscoord rowHeightAsPixels = nsPresContext::AppUnitsToIntCSSPixels(mRowHeight);
     906                 : 
     907               0 :   if (aParts.mVScrollbar) {
     908               0 :     nsAutoString curPos;
     909               0 :     curPos.AppendInt(mTopRowIndex*rowHeightAsPixels);
     910                 :     aParts.mVScrollbarContent->
     911               0 :       SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curPos, true);
     912                 :   }
     913                 : 
     914               0 :   if (aParts.mHScrollbar) {
     915               0 :     nsAutoString curPos;
     916               0 :     curPos.AppendInt(mHorzPosition);
     917                 :     aParts.mHScrollbarContent->
     918               0 :       SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curPos, true);
     919                 :   }
     920               0 : }
     921                 : 
     922                 : void
     923               0 : nsTreeBodyFrame::CheckOverflow(const ScrollParts& aParts)
     924                 : {
     925               0 :   bool verticalOverflowChanged = false;
     926               0 :   bool horizontalOverflowChanged = false;
     927                 : 
     928               0 :   if (!mVerticalOverflow && mRowCount > mPageLength) {
     929               0 :     mVerticalOverflow = true;
     930               0 :     verticalOverflowChanged = true;
     931                 :   }
     932               0 :   else if (mVerticalOverflow && mRowCount <= mPageLength) {
     933               0 :     mVerticalOverflow = false;
     934               0 :     verticalOverflowChanged = true;
     935                 :   }
     936                 : 
     937               0 :   if (aParts.mColumnsFrame) {
     938               0 :     nsRect bounds = aParts.mColumnsFrame->GetRect();
     939               0 :     if (bounds.width != 0) {
     940                 :       /* Ignore overflows that are less than half a pixel. Yes these happen
     941                 :          all over the place when flex boxes are compressed real small. 
     942                 :          Probably a result of a rounding errors somewhere in the layout code. */
     943               0 :       bounds.width += nsPresContext::CSSPixelsToAppUnits(0.5f);
     944               0 :       if (!mHorizontalOverflow && bounds.width < mHorzWidth) {
     945               0 :         mHorizontalOverflow = true;
     946               0 :         horizontalOverflowChanged = true;
     947               0 :       } else if (mHorizontalOverflow && bounds.width >= mHorzWidth) {
     948               0 :         mHorizontalOverflow = false;
     949               0 :         horizontalOverflowChanged = true;
     950                 :       }
     951                 :     }
     952                 :   }
     953                 :  
     954               0 :   nsRefPtr<nsPresContext> presContext = PresContext();
     955               0 :   nsCOMPtr<nsIContent> content = mContent;
     956                 : 
     957               0 :   if (verticalOverflowChanged) {
     958                 :     nsScrollPortEvent event(true, mVerticalOverflow ? NS_SCROLLPORT_OVERFLOW
     959               0 :                             : NS_SCROLLPORT_UNDERFLOW, nsnull);
     960               0 :     event.orient = nsScrollPortEvent::vertical;
     961               0 :     nsEventDispatcher::Dispatch(content, presContext, &event);
     962                 :   }
     963                 : 
     964               0 :   if (horizontalOverflowChanged) {
     965                 :     nsScrollPortEvent event(true,
     966                 :                             mHorizontalOverflow ? NS_SCROLLPORT_OVERFLOW
     967               0 :                             : NS_SCROLLPORT_UNDERFLOW, nsnull);
     968               0 :     event.orient = nsScrollPortEvent::horizontal;
     969               0 :     nsEventDispatcher::Dispatch(content, presContext, &event);
     970                 :   }
     971               0 : }
     972                 : 
     973                 : void
     974               0 : nsTreeBodyFrame::InvalidateScrollbars(const ScrollParts& aParts, nsWeakFrame& aWeakColumnsFrame)
     975                 : {
     976               0 :   if (mUpdateBatchNest || !mView)
     977               0 :     return;
     978               0 :   nsWeakFrame weakFrame(this);
     979                 : 
     980               0 :   if (aParts.mVScrollbar) {
     981                 :     // Do Vertical Scrollbar 
     982               0 :     nsAutoString maxposStr;
     983                 : 
     984               0 :     nscoord rowHeightAsPixels = nsPresContext::AppUnitsToIntCSSPixels(mRowHeight);
     985                 : 
     986               0 :     PRInt32 size = rowHeightAsPixels * (mRowCount > mPageLength ? mRowCount - mPageLength : 0);
     987               0 :     maxposStr.AppendInt(size);
     988                 :     aParts.mVScrollbarContent->
     989               0 :       SetAttr(kNameSpaceID_None, nsGkAtoms::maxpos, maxposStr, true);
     990               0 :     ENSURE_TRUE(weakFrame.IsAlive());
     991                 : 
     992                 :     // Also set our page increment and decrement.
     993               0 :     nscoord pageincrement = mPageLength*rowHeightAsPixels;
     994               0 :     nsAutoString pageStr;
     995               0 :     pageStr.AppendInt(pageincrement);
     996                 :     aParts.mVScrollbarContent->
     997               0 :       SetAttr(kNameSpaceID_None, nsGkAtoms::pageincrement, pageStr, true);
     998               0 :     ENSURE_TRUE(weakFrame.IsAlive());
     999                 :   }
    1000                 : 
    1001               0 :   if (aParts.mHScrollbar && aParts.mColumnsFrame && aWeakColumnsFrame.IsAlive()) {
    1002                 :     // And now Horizontal scrollbar
    1003               0 :     nsRect bounds = aParts.mColumnsFrame->GetRect();
    1004               0 :     nsAutoString maxposStr;
    1005                 : 
    1006               0 :     maxposStr.AppendInt(mHorzWidth > bounds.width ? mHorzWidth - bounds.width : 0);
    1007                 :     aParts.mHScrollbarContent->
    1008               0 :       SetAttr(kNameSpaceID_None, nsGkAtoms::maxpos, maxposStr, true);
    1009               0 :     ENSURE_TRUE(weakFrame.IsAlive());
    1010                 :   
    1011               0 :     nsAutoString pageStr;
    1012               0 :     pageStr.AppendInt(bounds.width);
    1013                 :     aParts.mHScrollbarContent->
    1014               0 :       SetAttr(kNameSpaceID_None, nsGkAtoms::pageincrement, pageStr, true);
    1015               0 :     ENSURE_TRUE(weakFrame.IsAlive());
    1016                 :   
    1017               0 :     pageStr.Truncate();
    1018               0 :     pageStr.AppendInt(nsPresContext::CSSPixelsToAppUnits(16));
    1019                 :     aParts.mHScrollbarContent->
    1020               0 :       SetAttr(kNameSpaceID_None, nsGkAtoms::increment, pageStr, true);
    1021                 :   }
    1022                 : }
    1023                 : 
    1024                 : // Takes client x/y in pixels, converts them to appunits, and converts into
    1025                 : // values relative to this nsTreeBodyFrame frame.
    1026                 : nsPoint
    1027               0 : nsTreeBodyFrame::AdjustClientCoordsToBoxCoordSpace(PRInt32 aX, PRInt32 aY)
    1028                 : {
    1029                 :   nsPoint point(nsPresContext::CSSPixelsToAppUnits(aX),
    1030               0 :                 nsPresContext::CSSPixelsToAppUnits(aY));
    1031                 : 
    1032               0 :   nsPresContext* presContext = PresContext();
    1033               0 :   point -= GetOffsetTo(presContext->GetPresShell()->GetRootFrame());
    1034                 : 
    1035                 :   // Adjust by the inner box coords, so that we're in the inner box's
    1036                 :   // coordinate space.
    1037               0 :   point -= mInnerBox.TopLeft();
    1038                 :   return point;
    1039                 : } // AdjustClientCoordsToBoxCoordSpace
    1040                 : 
    1041                 : nsresult
    1042               0 : nsTreeBodyFrame::GetRowAt(PRInt32 aX, PRInt32 aY, PRInt32* _retval)
    1043                 : {
    1044               0 :   if (!mView)
    1045               0 :     return NS_OK;
    1046                 : 
    1047               0 :   nsPoint point = AdjustClientCoordsToBoxCoordSpace(aX, aY);
    1048                 : 
    1049                 :   // Check if the coordinates are above our visible space.
    1050               0 :   if (point.y < 0) {
    1051               0 :     *_retval = -1;
    1052               0 :     return NS_OK;
    1053                 :   }
    1054                 : 
    1055               0 :   *_retval = GetRowAt(point.x, point.y);
    1056                 : 
    1057               0 :   return NS_OK;
    1058                 : }
    1059                 : 
    1060                 : nsresult
    1061               0 : nsTreeBodyFrame::GetCellAt(PRInt32 aX, PRInt32 aY, PRInt32* aRow, nsITreeColumn** aCol,
    1062                 :                            nsACString& aChildElt)
    1063                 : {
    1064               0 :   if (!mView)
    1065               0 :     return NS_OK;
    1066                 : 
    1067               0 :   nsPoint point = AdjustClientCoordsToBoxCoordSpace(aX, aY);
    1068                 : 
    1069                 :   // Check if the coordinates are above our visible space.
    1070               0 :   if (point.y < 0) {
    1071               0 :     *aRow = -1;
    1072               0 :     return NS_OK;
    1073                 :   }
    1074                 : 
    1075                 :   nsTreeColumn* col;
    1076                 :   nsIAtom* child;
    1077               0 :   GetCellAt(point.x, point.y, aRow, &col, &child);
    1078                 : 
    1079               0 :   if (col) {
    1080               0 :     NS_ADDREF(*aCol = col);
    1081               0 :     if (child == nsCSSAnonBoxes::moztreecell)
    1082               0 :       aChildElt.AssignLiteral("cell");
    1083               0 :     else if (child == nsCSSAnonBoxes::moztreetwisty)
    1084               0 :       aChildElt.AssignLiteral("twisty");
    1085               0 :     else if (child == nsCSSAnonBoxes::moztreeimage)
    1086               0 :       aChildElt.AssignLiteral("image");
    1087               0 :     else if (child == nsCSSAnonBoxes::moztreecelltext)
    1088               0 :       aChildElt.AssignLiteral("text");
    1089                 :   }
    1090                 : 
    1091               0 :   return NS_OK;
    1092                 : }
    1093                 : 
    1094                 : 
    1095                 : //
    1096                 : // GetCoordsForCellItem
    1097                 : //
    1098                 : // Find the x/y location and width/height (all in PIXELS) of the given object
    1099                 : // in the given column. 
    1100                 : //
    1101                 : // XXX IMPORTANT XXX:
    1102                 : // Hyatt says in the bug for this, that the following needs to be done:
    1103                 : // (1) You need to deal with overflow when computing cell rects.  See other column 
    1104                 : // iteration examples... if you don't deal with this, you'll mistakenly extend the 
    1105                 : // cell into the scrollbar's rect.
    1106                 : //
    1107                 : // (2) You are adjusting the cell rect by the *row" border padding.  That's 
    1108                 : // wrong.  You need to first adjust a row rect by its border/padding, and then the 
    1109                 : // cell rect fits inside the adjusted row rect.  It also can have border/padding 
    1110                 : // as well as margins.  The vertical direction isn't that important, but you need 
    1111                 : // to get the horizontal direction right.
    1112                 : //
    1113                 : // (3) GetImageSize() does not include margins (but it does include border/padding).  
    1114                 : // You need to make sure to add in the image's margins as well.
    1115                 : //
    1116                 : nsresult
    1117               0 : nsTreeBodyFrame::GetCoordsForCellItem(PRInt32 aRow, nsITreeColumn* aCol, const nsACString& aElement, 
    1118                 :                                       PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight)
    1119                 : {
    1120               0 :   *aX = 0;
    1121               0 :   *aY = 0;
    1122               0 :   *aWidth = 0;
    1123               0 :   *aHeight = 0;
    1124                 : 
    1125               0 :   bool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
    1126               0 :   nscoord currX = mInnerBox.x - mHorzPosition;
    1127                 : 
    1128                 :   // The Rect for the requested item. 
    1129               0 :   nsRect theRect;
    1130                 : 
    1131               0 :   nsPresContext* presContext = PresContext();
    1132                 : 
    1133               0 :   for (nsTreeColumn* currCol = mColumns->GetFirstColumn(); currCol; currCol = currCol->GetNext()) {
    1134                 : 
    1135                 :     // The Rect for the current cell.
    1136                 :     nscoord colWidth;
    1137                 : #ifdef DEBUG
    1138                 :     nsresult rv =
    1139                 : #endif
    1140               0 :       currCol->GetWidthInTwips(this, &colWidth);
    1141               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "invalid column");
    1142                 : 
    1143                 :     nsRect cellRect(currX, mInnerBox.y + mRowHeight * (aRow - mTopRowIndex),
    1144               0 :                     colWidth, mRowHeight);
    1145                 : 
    1146                 :     // Check the ID of the current column to see if it matches. If it doesn't 
    1147                 :     // increment the current X value and continue to the next column.
    1148               0 :     if (currCol != aCol) {
    1149               0 :       currX += cellRect.width;
    1150               0 :       continue;
    1151                 :     }
    1152                 :     // Now obtain the properties for our cell.
    1153               0 :     PrefillPropertyArray(aRow, currCol);
    1154               0 :     mView->GetCellProperties(aRow, currCol, mScratchArray);
    1155                 : 
    1156               0 :     nsStyleContext* rowContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreerow);
    1157                 : 
    1158                 :     // We don't want to consider any of the decorations that may be present
    1159                 :     // on the current row, so we have to deflate the rect by the border and 
    1160                 :     // padding and offset its left and top coordinates appropriately. 
    1161               0 :     AdjustForBorderPadding(rowContext, cellRect);
    1162                 : 
    1163               0 :     nsStyleContext* cellContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecell);
    1164                 : 
    1165               0 :     NS_NAMED_LITERAL_CSTRING(cell, "cell");
    1166               0 :     if (currCol->IsCycler() || cell.Equals(aElement)) {
    1167                 :       // If the current Column is a Cycler, then the Rect is just the cell - the margins. 
    1168                 :       // Similarly, if we're just being asked for the cell rect, provide it. 
    1169                 : 
    1170               0 :       theRect = cellRect;
    1171               0 :       nsMargin cellMargin;
    1172               0 :       cellContext->GetStyleMargin()->GetMargin(cellMargin);
    1173               0 :       theRect.Deflate(cellMargin);
    1174                 :       break;
    1175                 :     }
    1176                 : 
    1177                 :     // Since we're not looking for the cell, and since the cell isn't a cycler,
    1178                 :     // we're looking for some subcomponent, and now we need to subtract the 
    1179                 :     // borders and padding of the cell from cellRect so this does not 
    1180                 :     // interfere with our computations.
    1181               0 :     AdjustForBorderPadding(cellContext, cellRect);
    1182                 : 
    1183                 :     nsRefPtr<nsRenderingContext> rc =
    1184               0 :       presContext->PresShell()->GetReferenceRenderingContext();
    1185               0 :     if (!rc)
    1186               0 :       return NS_ERROR_OUT_OF_MEMORY;
    1187                 : 
    1188                 :     // Now we'll start making our way across the cell, starting at the edge of 
    1189                 :     // the cell and proceeding until we hit the right edge. |cellX| is the 
    1190                 :     // working X value that we will increment as we crawl from left to right.
    1191               0 :     nscoord cellX = cellRect.x;
    1192               0 :     nscoord remainWidth = cellRect.width;
    1193                 : 
    1194               0 :     if (currCol->IsPrimary()) {
    1195                 :       // If the current Column is a Primary, then we need to take into account the indentation
    1196                 :       // and possibly a twisty. 
    1197                 : 
    1198                 :       // The amount of indentation is the indentation width (|mIndentation|) by the level. 
    1199                 :       PRInt32 level;
    1200               0 :       mView->GetLevel(aRow, &level);
    1201               0 :       if (!isRTL)
    1202               0 :         cellX += mIndentation * level;
    1203               0 :       remainWidth -= mIndentation * level;
    1204                 : 
    1205                 :       // Find the twisty rect by computing its size. 
    1206               0 :       nsRect imageRect;
    1207               0 :       nsRect twistyRect(cellRect);
    1208               0 :       nsStyleContext* twistyContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreetwisty);
    1209                 :       GetTwistyRect(aRow, currCol, imageRect, twistyRect, presContext,
    1210               0 :                     *rc, twistyContext);
    1211                 : 
    1212               0 :       if (NS_LITERAL_CSTRING("twisty").Equals(aElement)) {
    1213                 :         // If we're looking for the twisty Rect, just return the size
    1214               0 :         theRect = twistyRect;
    1215                 :         break;
    1216                 :       }
    1217                 :       
    1218                 :       // Now we need to add in the margins of the twisty element, so that we 
    1219                 :       // can find the offset of the next element in the cell. 
    1220               0 :       nsMargin twistyMargin;
    1221               0 :       twistyContext->GetStyleMargin()->GetMargin(twistyMargin);
    1222               0 :       twistyRect.Inflate(twistyMargin);
    1223                 : 
    1224                 :       // Adjust our working X value with the twisty width (image size, margins,
    1225                 :       // borders, padding.
    1226               0 :       if (!isRTL)
    1227               0 :         cellX += twistyRect.width;
    1228                 :     }
    1229                 : 
    1230                 :     // Cell Image
    1231               0 :     nsStyleContext* imageContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeimage);
    1232                 : 
    1233               0 :     nsRect imageSize = GetImageSize(aRow, currCol, false, imageContext);
    1234               0 :     if (NS_LITERAL_CSTRING("image").Equals(aElement)) {
    1235               0 :       theRect = imageSize;
    1236               0 :       theRect.x = cellX;
    1237               0 :       theRect.y = cellRect.y;
    1238                 :       break;
    1239                 :     }
    1240                 : 
    1241                 :     // Add in the margins of the cell image.
    1242               0 :     nsMargin imageMargin;
    1243               0 :     imageContext->GetStyleMargin()->GetMargin(imageMargin);
    1244               0 :     imageSize.Inflate(imageMargin);
    1245                 : 
    1246                 :     // Increment cellX by the image width
    1247               0 :     if (!isRTL)
    1248               0 :       cellX += imageSize.width;
    1249                 :     
    1250                 :     // Cell Text 
    1251               0 :     nsAutoString cellText;
    1252               0 :     mView->GetCellText(aRow, currCol, cellText);
    1253                 :     // We're going to measure this text so we need to ensure bidi is enabled if
    1254                 :     // necessary
    1255               0 :     CheckTextForBidi(cellText);
    1256                 : 
    1257                 :     // Create a scratch rect to represent the text rectangle, with the current 
    1258                 :     // X and Y coords, and a guess at the width and height. The width is the 
    1259                 :     // remaining width we have left to traverse in the cell, which will be the
    1260                 :     // widest possible value for the text rect, and the row height. 
    1261               0 :     nsRect textRect(cellX, cellRect.y, remainWidth, cellRect.height);
    1262                 : 
    1263                 :     // Measure the width of the text. If the width of the text is greater than 
    1264                 :     // the remaining width available, then we just assume that the text has 
    1265                 :     // been cropped and use the remaining rect as the text Rect. Otherwise,
    1266                 :     // we add in borders and padding to the text dimension and give that back. 
    1267               0 :     nsStyleContext* textContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecelltext);
    1268                 : 
    1269               0 :     nsRefPtr<nsFontMetrics> fm;
    1270                 :     nsLayoutUtils::GetFontMetricsForStyleContext(textContext,
    1271               0 :                                                  getter_AddRefs(fm));
    1272               0 :     nscoord height = fm->MaxHeight();
    1273                 : 
    1274               0 :     nsMargin textMargin;
    1275               0 :     textContext->GetStyleMargin()->GetMargin(textMargin);
    1276               0 :     textRect.Deflate(textMargin);
    1277                 : 
    1278                 :     // Center the text. XXX Obey vertical-align style prop?
    1279               0 :     if (height < textRect.height) {
    1280               0 :       textRect.y += (textRect.height - height) / 2;
    1281               0 :       textRect.height = height;
    1282                 :     }
    1283                 : 
    1284               0 :     nsMargin bp(0,0,0,0);
    1285               0 :     GetBorderPadding(textContext, bp);
    1286               0 :     textRect.height += bp.top + bp.bottom;
    1287                 : 
    1288               0 :     rc->SetFont(fm);
    1289               0 :     AdjustForCellText(cellText, aRow, currCol, *rc, textRect);
    1290                 : 
    1291               0 :     theRect = textRect;
    1292                 :   }
    1293                 : 
    1294               0 :   if (isRTL)
    1295               0 :     theRect.x = mInnerBox.width - theRect.x - theRect.width;
    1296                 : 
    1297               0 :   *aX = nsPresContext::AppUnitsToIntCSSPixels(theRect.x);
    1298               0 :   *aY = nsPresContext::AppUnitsToIntCSSPixels(theRect.y);
    1299               0 :   *aWidth = nsPresContext::AppUnitsToIntCSSPixels(theRect.width);
    1300               0 :   *aHeight = nsPresContext::AppUnitsToIntCSSPixels(theRect.height);
    1301                 : 
    1302               0 :   return NS_OK;
    1303                 : }
    1304                 : 
    1305                 : PRInt32
    1306               0 : nsTreeBodyFrame::GetRowAt(PRInt32 aX, PRInt32 aY)
    1307                 : {
    1308                 :   // Now just mod by our total inner box height and add to our top row index.
    1309               0 :   PRInt32 row = (aY/mRowHeight)+mTopRowIndex;
    1310                 : 
    1311                 :   // Check if the coordinates are below our visible space (or within our visible
    1312                 :   // space but below any row).
    1313               0 :   if (row > mTopRowIndex + mPageLength || row >= mRowCount)
    1314               0 :     return -1;
    1315                 : 
    1316               0 :   return row;
    1317                 : }
    1318                 : 
    1319                 : void
    1320               0 : nsTreeBodyFrame::CheckTextForBidi(nsAutoString& aText)
    1321                 : {
    1322                 :   // We could check to see whether the prescontext already has bidi enabled,
    1323                 :   // but usually it won't, so it's probably faster to avoid the call to
    1324                 :   // GetPresContext() when it's not needed.
    1325               0 :   if (HasRTLChars(aText)) {
    1326               0 :     PresContext()->SetBidiEnabled();
    1327                 :   }
    1328               0 : }
    1329                 : 
    1330                 : void
    1331               0 : nsTreeBodyFrame::AdjustForCellText(nsAutoString& aText,
    1332                 :                                    PRInt32 aRowIndex,  nsTreeColumn* aColumn,
    1333                 :                                    nsRenderingContext& aRenderingContext,
    1334                 :                                    nsRect& aTextRect)
    1335                 : {
    1336               0 :   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
    1337                 : 
    1338                 :   nscoord width =
    1339               0 :     nsLayoutUtils::GetStringWidth(this, &aRenderingContext, aText.get(), aText.Length());
    1340               0 :   nscoord maxWidth = aTextRect.width;
    1341                 : 
    1342               0 :   if (aColumn->Overflow()) {
    1343                 :     nsresult rv;
    1344               0 :     nsTreeColumn* nextColumn = aColumn->GetNext();
    1345               0 :     while (nextColumn && width > maxWidth) {
    1346               0 :       while (nextColumn) {
    1347                 :         nscoord width;
    1348               0 :         rv = nextColumn->GetWidthInTwips(this, &width);
    1349               0 :         NS_ASSERTION(NS_SUCCEEDED(rv), "nextColumn is invalid");
    1350                 : 
    1351               0 :         if (width != 0)
    1352               0 :           break;
    1353                 : 
    1354               0 :         nextColumn = nextColumn->GetNext();
    1355                 :       }
    1356                 : 
    1357               0 :       if (nextColumn) {
    1358               0 :         nsAutoString nextText;
    1359               0 :         mView->GetCellText(aRowIndex, nextColumn, nextText);
    1360                 :         // We don't measure or draw this text so no need to check it for
    1361                 :         // bidi-ness
    1362                 : 
    1363               0 :         if (nextText.Length() == 0) {
    1364                 :           nscoord width;
    1365               0 :           rv = nextColumn->GetWidthInTwips(this, &width);
    1366               0 :           NS_ASSERTION(NS_SUCCEEDED(rv), "nextColumn is invalid");
    1367                 : 
    1368               0 :           maxWidth += width;
    1369                 : 
    1370               0 :           nextColumn = nextColumn->GetNext();
    1371                 :         }
    1372                 :         else {
    1373               0 :           nextColumn = nsnull;
    1374                 :         }
    1375                 :       }
    1376                 :     }
    1377                 :   }
    1378                 : 
    1379               0 :   if (width > maxWidth) {
    1380                 :     // See if the width is even smaller than the ellipsis
    1381                 :     // If so, clear the text completely.
    1382               0 :     const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
    1383               0 :     aRenderingContext.SetTextRunRTL(false);
    1384               0 :     nscoord ellipsisWidth = aRenderingContext.GetWidth(kEllipsis);
    1385                 : 
    1386               0 :     width = maxWidth;
    1387               0 :     if (ellipsisWidth > width)
    1388               0 :       aText.SetLength(0);
    1389               0 :     else if (ellipsisWidth == width)
    1390               0 :       aText.Assign(kEllipsis);
    1391                 :     else {
    1392                 :       // We will be drawing an ellipsis, thank you very much.
    1393                 :       // Subtract out the required width of the ellipsis.
    1394                 :       // This is the total remaining width we have to play with.
    1395               0 :       width -= ellipsisWidth;
    1396                 : 
    1397                 :       // Now we crop.
    1398               0 :       switch (aColumn->GetCropStyle()) {
    1399                 :         default:
    1400                 :         case 0: {
    1401                 :           // Crop right.
    1402                 :           nscoord cwidth;
    1403               0 :           nscoord twidth = 0;
    1404               0 :           PRUint32 length = aText.Length();
    1405                 :           PRUint32 i;
    1406               0 :           for (i = 0; i < length; ++i) {
    1407               0 :             PRUnichar ch = aText[i];
    1408                 :             // XXX this is horrible and doesn't handle clusters
    1409               0 :             cwidth = aRenderingContext.GetWidth(ch);
    1410               0 :             if (twidth + cwidth > width)
    1411               0 :               break;
    1412               0 :             twidth += cwidth;
    1413                 :           }
    1414               0 :           aText.Truncate(i);
    1415               0 :           aText.Append(kEllipsis);
    1416                 :         }
    1417               0 :         break;
    1418                 : 
    1419                 :         case 2: {
    1420                 :           // Crop left.
    1421                 :           nscoord cwidth;
    1422               0 :           nscoord twidth = 0;
    1423               0 :           PRInt32 length = aText.Length();
    1424                 :           PRInt32 i;
    1425               0 :           for (i=length-1; i >= 0; --i) {
    1426               0 :             PRUnichar ch = aText[i];
    1427               0 :             cwidth = aRenderingContext.GetWidth(ch);
    1428               0 :             if (twidth + cwidth > width)
    1429               0 :               break;
    1430               0 :             twidth += cwidth;
    1431                 :           }
    1432                 : 
    1433               0 :           nsAutoString copy;
    1434               0 :           aText.Right(copy, length-1-i);
    1435               0 :           aText.Assign(kEllipsis);
    1436               0 :           aText += copy;
    1437                 :         }
    1438               0 :         break;
    1439                 : 
    1440                 :         case 1:
    1441                 :         {
    1442                 :           // Crop center.
    1443               0 :           nsAutoString leftStr, rightStr;
    1444               0 :           nscoord cwidth, twidth = 0;
    1445               0 :           PRInt32 length = aText.Length();
    1446               0 :           PRInt32 rightPos = length - 1;
    1447               0 :           for (PRInt32 leftPos = 0; leftPos < rightPos; ++leftPos) {
    1448               0 :             PRUnichar ch = aText[leftPos];
    1449               0 :             cwidth = aRenderingContext.GetWidth(ch);
    1450               0 :             twidth += cwidth;
    1451               0 :             if (twidth > width)
    1452               0 :               break;
    1453               0 :             leftStr.Append(ch);
    1454                 : 
    1455               0 :             ch = aText[rightPos];
    1456               0 :             cwidth = aRenderingContext.GetWidth(ch);
    1457               0 :             twidth += cwidth;
    1458               0 :             if (twidth > width)
    1459               0 :               break;
    1460               0 :             rightStr.Insert(ch, 0);
    1461               0 :             --rightPos;
    1462                 :           }
    1463               0 :           aText = leftStr;
    1464               0 :           aText.Append(kEllipsis);
    1465               0 :           aText += rightStr;
    1466                 :         }
    1467               0 :         break;
    1468                 :       }
    1469                 :     }
    1470                 : 
    1471               0 :     width = nsLayoutUtils::GetStringWidth(this, &aRenderingContext, aText.get(), aText.Length());
    1472                 :   }
    1473                 : 
    1474               0 :   switch (aColumn->GetTextAlignment()) {
    1475                 :     case NS_STYLE_TEXT_ALIGN_RIGHT: {
    1476               0 :       aTextRect.x += aTextRect.width - width;
    1477                 :     }
    1478               0 :     break;
    1479                 :     case NS_STYLE_TEXT_ALIGN_CENTER: {
    1480               0 :       aTextRect.x += (aTextRect.width - width) / 2;
    1481                 :     }
    1482               0 :     break;
    1483                 :   }
    1484                 : 
    1485               0 :   aTextRect.width = width;
    1486               0 : }
    1487                 : 
    1488                 : nsIAtom*
    1489               0 : nsTreeBodyFrame::GetItemWithinCellAt(nscoord aX, const nsRect& aCellRect, 
    1490                 :                                      PRInt32 aRowIndex,
    1491                 :                                      nsTreeColumn* aColumn)
    1492                 : {
    1493               0 :   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
    1494                 : 
    1495                 :   // Obtain the properties for our cell.
    1496               0 :   PrefillPropertyArray(aRowIndex, aColumn);
    1497               0 :   mView->GetCellProperties(aRowIndex, aColumn, mScratchArray);
    1498                 : 
    1499                 :   // Resolve style for the cell.
    1500               0 :   nsStyleContext* cellContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecell);
    1501                 : 
    1502                 :   // Obtain the margins for the cell and then deflate our rect by that 
    1503                 :   // amount.  The cell is assumed to be contained within the deflated rect.
    1504               0 :   nsRect cellRect(aCellRect);
    1505               0 :   nsMargin cellMargin;
    1506               0 :   cellContext->GetStyleMargin()->GetMargin(cellMargin);
    1507               0 :   cellRect.Deflate(cellMargin);
    1508                 : 
    1509                 :   // Adjust the rect for its border and padding.
    1510               0 :   AdjustForBorderPadding(cellContext, cellRect);
    1511                 : 
    1512               0 :   if (aX < cellRect.x || aX >= cellRect.x + cellRect.width) {
    1513                 :     // The user clicked within the cell's margins/borders/padding.  This constitutes a click on the cell.
    1514               0 :     return nsCSSAnonBoxes::moztreecell;
    1515                 :   }
    1516                 : 
    1517               0 :   nscoord currX = cellRect.x;
    1518               0 :   nscoord remainingWidth = cellRect.width;
    1519                 : 
    1520                 :   // Handle right alignment hit testing.
    1521               0 :   bool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
    1522                 : 
    1523               0 :   nsPresContext* presContext = PresContext();
    1524                 :   nsRefPtr<nsRenderingContext> rc =
    1525               0 :     presContext->PresShell()->GetReferenceRenderingContext();
    1526               0 :   if (!rc)
    1527               0 :     return nsCSSAnonBoxes::moztreecell;
    1528                 : 
    1529               0 :   if (aColumn->IsPrimary()) {
    1530                 :     // If we're the primary column, we have indentation and a twisty.
    1531                 :     PRInt32 level;
    1532               0 :     mView->GetLevel(aRowIndex, &level);
    1533                 : 
    1534               0 :     if (!isRTL)
    1535               0 :       currX += mIndentation*level;
    1536               0 :     remainingWidth -= mIndentation*level;
    1537                 : 
    1538               0 :     if ((isRTL && aX > currX + remainingWidth) ||
    1539               0 :         (!isRTL && aX < currX)) {
    1540                 :       // The user clicked within the indentation.
    1541               0 :       return nsCSSAnonBoxes::moztreecell;
    1542                 :     }
    1543                 : 
    1544                 :     // Always leave space for the twisty.
    1545               0 :     nsRect twistyRect(currX, cellRect.y, remainingWidth, cellRect.height);
    1546               0 :     bool hasTwisty = false;
    1547               0 :     bool isContainer = false;
    1548               0 :     mView->IsContainer(aRowIndex, &isContainer);
    1549               0 :     if (isContainer) {
    1550               0 :       bool isContainerEmpty = false;
    1551               0 :       mView->IsContainerEmpty(aRowIndex, &isContainerEmpty);
    1552               0 :       if (!isContainerEmpty)
    1553               0 :         hasTwisty = true;
    1554                 :     }
    1555                 : 
    1556                 :     // Resolve style for the twisty.
    1557               0 :     nsStyleContext* twistyContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreetwisty);
    1558                 : 
    1559               0 :     nsRect imageSize;
    1560                 :     GetTwistyRect(aRowIndex, aColumn, imageSize, twistyRect, presContext,
    1561               0 :                   *rc, twistyContext);
    1562                 : 
    1563                 :     // We will treat a click as hitting the twisty if it happens on the margins, borders, padding,
    1564                 :     // or content of the twisty object.  By allowing a "slop" into the margin, we make it a little
    1565                 :     // bit easier for a user to hit the twisty.  (We don't want to be too picky here.)
    1566               0 :     nsMargin twistyMargin;
    1567               0 :     twistyContext->GetStyleMargin()->GetMargin(twistyMargin);
    1568               0 :     twistyRect.Inflate(twistyMargin);
    1569               0 :     if (isRTL)
    1570               0 :       twistyRect.x = currX + remainingWidth - twistyRect.width;
    1571                 : 
    1572                 :     // Now we test to see if aX is actually within the twistyRect.  If it is, and if the item should
    1573                 :     // have a twisty, then we return "twisty".  If it is within the rect but we shouldn't have a twisty,
    1574                 :     // then we return "cell".
    1575               0 :     if (aX >= twistyRect.x && aX < twistyRect.x + twistyRect.width) {
    1576               0 :       if (hasTwisty)
    1577               0 :         return nsCSSAnonBoxes::moztreetwisty;
    1578                 :       else
    1579               0 :         return nsCSSAnonBoxes::moztreecell;
    1580                 :     }
    1581                 : 
    1582               0 :     if (!isRTL)
    1583               0 :       currX += twistyRect.width;
    1584               0 :     remainingWidth -= twistyRect.width;    
    1585                 :   }
    1586                 :   
    1587                 :   // Now test to see if the user hit the icon for the cell.
    1588               0 :   nsRect iconRect(currX, cellRect.y, remainingWidth, cellRect.height);
    1589                 :   
    1590                 :   // Resolve style for the image.
    1591               0 :   nsStyleContext* imageContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeimage);
    1592                 : 
    1593               0 :   nsRect iconSize = GetImageSize(aRowIndex, aColumn, false, imageContext);
    1594               0 :   nsMargin imageMargin;
    1595               0 :   imageContext->GetStyleMargin()->GetMargin(imageMargin);
    1596               0 :   iconSize.Inflate(imageMargin);
    1597               0 :   iconRect.width = iconSize.width;
    1598               0 :   if (isRTL)
    1599               0 :     iconRect.x = currX + remainingWidth - iconRect.width;
    1600                 : 
    1601               0 :   if (aX >= iconRect.x && aX < iconRect.x + iconRect.width) {
    1602                 :     // The user clicked on the image.
    1603               0 :     return nsCSSAnonBoxes::moztreeimage;
    1604                 :   }
    1605                 : 
    1606               0 :   if (!isRTL)
    1607               0 :     currX += iconRect.width;
    1608               0 :   remainingWidth -= iconRect.width;    
    1609                 : 
    1610               0 :   nsAutoString cellText;
    1611               0 :   mView->GetCellText(aRowIndex, aColumn, cellText);
    1612                 :   // We're going to measure this text so we need to ensure bidi is enabled if
    1613                 :   // necessary
    1614               0 :   CheckTextForBidi(cellText);
    1615                 : 
    1616               0 :   nsRect textRect(currX, cellRect.y, remainingWidth, cellRect.height);
    1617                 : 
    1618               0 :   nsStyleContext* textContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecelltext);
    1619                 : 
    1620               0 :   nsMargin textMargin;
    1621               0 :   textContext->GetStyleMargin()->GetMargin(textMargin);
    1622               0 :   textRect.Deflate(textMargin);
    1623                 : 
    1624               0 :   AdjustForBorderPadding(textContext, textRect);
    1625                 : 
    1626               0 :   nsRefPtr<nsFontMetrics> fm;
    1627                 :   nsLayoutUtils::GetFontMetricsForStyleContext(textContext,
    1628               0 :                                                getter_AddRefs(fm));
    1629               0 :   rc->SetFont(fm);
    1630                 : 
    1631               0 :   AdjustForCellText(cellText, aRowIndex, aColumn, *rc, textRect);
    1632                 : 
    1633               0 :   if (aX >= textRect.x && aX < textRect.x + textRect.width)
    1634               0 :     return nsCSSAnonBoxes::moztreecelltext;
    1635                 :   else
    1636               0 :     return nsCSSAnonBoxes::moztreecell;
    1637                 : }
    1638                 : 
    1639                 : void
    1640               0 : nsTreeBodyFrame::GetCellAt(nscoord aX, nscoord aY, PRInt32* aRow,
    1641                 :                            nsTreeColumn** aCol, nsIAtom** aChildElt)
    1642                 : {
    1643               0 :   *aCol = nsnull;
    1644               0 :   *aChildElt = nsnull;
    1645                 : 
    1646               0 :   *aRow = GetRowAt(aX, aY);
    1647               0 :   if (*aRow < 0)
    1648               0 :     return;
    1649                 : 
    1650                 :   // Determine the column hit.
    1651               0 :   for (nsTreeColumn* currCol = mColumns->GetFirstColumn(); currCol; 
    1652                 :        currCol = currCol->GetNext()) {
    1653               0 :     nsRect cellRect;
    1654                 :     nsresult rv = currCol->GetRect(this,
    1655                 :                                    mInnerBox.y +
    1656                 :                                          mRowHeight * (*aRow - mTopRowIndex),
    1657                 :                                    mRowHeight,
    1658               0 :                                    &cellRect);
    1659               0 :     if (NS_FAILED(rv)) {
    1660               0 :       NS_NOTREACHED("column has no frame");
    1661               0 :       continue;
    1662                 :     }
    1663                 : 
    1664               0 :     if (!OffsetForHorzScroll(cellRect, false))
    1665               0 :       continue;
    1666                 : 
    1667               0 :     if (aX >= cellRect.x && aX < cellRect.x + cellRect.width) {
    1668                 :       // We know the column hit now.
    1669               0 :       *aCol = currCol;
    1670                 : 
    1671               0 :       if (currCol->IsCycler())
    1672                 :         // Cyclers contain only images.  Fill this in immediately and return.
    1673               0 :         *aChildElt = nsCSSAnonBoxes::moztreeimage;
    1674                 :       else
    1675               0 :         *aChildElt = GetItemWithinCellAt(aX, cellRect, *aRow, currCol);
    1676                 :       break;
    1677                 :     }
    1678                 :   }
    1679                 : }
    1680                 : 
    1681                 : nsresult
    1682               0 : nsTreeBodyFrame::GetCellWidth(PRInt32 aRow, nsTreeColumn* aCol,
    1683                 :                               nsRenderingContext* aRenderingContext,
    1684                 :                               nscoord& aDesiredSize, nscoord& aCurrentSize)
    1685                 : {
    1686               0 :   NS_PRECONDITION(aCol, "aCol must not be null");
    1687               0 :   NS_PRECONDITION(aRenderingContext, "aRenderingContext must not be null");
    1688                 : 
    1689                 :   // The rect for the current cell.
    1690                 :   nscoord colWidth;
    1691               0 :   nsresult rv = aCol->GetWidthInTwips(this, &colWidth);
    1692               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1693                 : 
    1694               0 :   nsRect cellRect(0, 0, colWidth, mRowHeight);
    1695                 : 
    1696               0 :   PRInt32 overflow = cellRect.x+cellRect.width-(mInnerBox.x+mInnerBox.width);
    1697               0 :   if (overflow > 0)
    1698               0 :     cellRect.width -= overflow;
    1699                 : 
    1700                 :   // Adjust borders and padding for the cell.
    1701               0 :   nsStyleContext* cellContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecell);
    1702               0 :   nsMargin bp(0,0,0,0);
    1703               0 :   GetBorderPadding(cellContext, bp);
    1704                 : 
    1705               0 :   aCurrentSize = cellRect.width;
    1706               0 :   aDesiredSize = bp.left + bp.right;
    1707                 : 
    1708               0 :   if (aCol->IsPrimary()) {
    1709                 :     // If the current Column is a Primary, then we need to take into account 
    1710                 :     // the indentation and possibly a twisty. 
    1711                 : 
    1712                 :     // The amount of indentation is the indentation width (|mIndentation|) by the level.
    1713                 :     PRInt32 level;
    1714               0 :     mView->GetLevel(aRow, &level);
    1715               0 :     aDesiredSize += mIndentation * level;
    1716                 :     
    1717                 :     // Find the twisty rect by computing its size.
    1718               0 :     nsStyleContext* twistyContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreetwisty);
    1719                 : 
    1720               0 :     nsRect imageSize;
    1721               0 :     nsRect twistyRect(cellRect);
    1722                 :     GetTwistyRect(aRow, aCol, imageSize, twistyRect, PresContext(),
    1723               0 :                   *aRenderingContext, twistyContext);
    1724                 : 
    1725                 :     // Add in the margins of the twisty element.
    1726               0 :     nsMargin twistyMargin;
    1727               0 :     twistyContext->GetStyleMargin()->GetMargin(twistyMargin);
    1728               0 :     twistyRect.Inflate(twistyMargin);
    1729                 : 
    1730               0 :     aDesiredSize += twistyRect.width;
    1731                 :   }
    1732                 : 
    1733               0 :   nsStyleContext* imageContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeimage);
    1734                 : 
    1735                 :   // Account for the width of the cell image.
    1736               0 :   nsRect imageSize = GetImageSize(aRow, aCol, false, imageContext);
    1737                 :   // Add in the margins of the cell image.
    1738               0 :   nsMargin imageMargin;
    1739               0 :   imageContext->GetStyleMargin()->GetMargin(imageMargin);
    1740               0 :   imageSize.Inflate(imageMargin);
    1741                 : 
    1742               0 :   aDesiredSize += imageSize.width;
    1743                 :   
    1744                 :   // Get the cell text.
    1745               0 :   nsAutoString cellText;
    1746               0 :   mView->GetCellText(aRow, aCol, cellText);
    1747                 :   // We're going to measure this text so we need to ensure bidi is enabled if
    1748                 :   // necessary
    1749               0 :   CheckTextForBidi(cellText);
    1750                 : 
    1751               0 :   nsStyleContext* textContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecelltext);
    1752                 : 
    1753                 :   // Get the borders and padding for the text.
    1754               0 :   GetBorderPadding(textContext, bp);
    1755                 : 
    1756               0 :   nsRefPtr<nsFontMetrics> fm;
    1757                 :   nsLayoutUtils::GetFontMetricsForStyleContext(textContext,
    1758               0 :                                                getter_AddRefs(fm));
    1759               0 :   aRenderingContext->SetFont(fm);
    1760                 : 
    1761                 :   // Get the width of the text itself
    1762                 :   nscoord width =
    1763               0 :     nsLayoutUtils::GetStringWidth(this, aRenderingContext, cellText.get(), cellText.Length());
    1764               0 :   nscoord totalTextWidth = width + bp.left + bp.right;
    1765               0 :   aDesiredSize += totalTextWidth;
    1766               0 :   return NS_OK;
    1767                 : }
    1768                 : 
    1769                 : nsresult
    1770               0 : nsTreeBodyFrame::IsCellCropped(PRInt32 aRow, nsITreeColumn* aCol, bool *_retval)
    1771                 : {  
    1772                 :   nscoord currentSize, desiredSize;
    1773                 :   nsresult rv;
    1774                 : 
    1775               0 :   nsRefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
    1776               0 :   if (!col)
    1777               0 :     return NS_ERROR_INVALID_ARG;
    1778                 : 
    1779                 :   nsRefPtr<nsRenderingContext> rc =
    1780               0 :     PresContext()->PresShell()->GetReferenceRenderingContext();
    1781               0 :   NS_ENSURE_TRUE(rc, NS_ERROR_FAILURE);
    1782                 : 
    1783               0 :   rv = GetCellWidth(aRow, col, rc, desiredSize, currentSize);
    1784               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1785                 : 
    1786               0 :   *_retval = desiredSize > currentSize;
    1787                 : 
    1788               0 :   return NS_OK;
    1789                 : }
    1790                 : 
    1791                 : void
    1792               0 : nsTreeBodyFrame::MarkDirtyIfSelect()
    1793                 : {
    1794               0 :   nsIContent* baseElement = GetBaseElement();
    1795                 : 
    1796               0 :   if (baseElement && baseElement->Tag() == nsGkAtoms::select &&
    1797               0 :       baseElement->IsHTML()) {
    1798                 :     // If we are an intrinsically sized select widget, we may need to
    1799                 :     // resize, if the widest item was removed or a new item was added.
    1800                 :     // XXX optimize this more
    1801                 : 
    1802               0 :     mStringWidth = -1;
    1803               0 :     PresContext()->PresShell()->FrameNeedsReflow(this,
    1804                 :                                                  nsIPresShell::eTreeChange,
    1805               0 :                                                  NS_FRAME_IS_DIRTY);
    1806                 :   }
    1807               0 : }
    1808                 : 
    1809                 : nsresult
    1810               0 : nsTreeBodyFrame::CreateTimer(const LookAndFeel::IntID aID,
    1811                 :                              nsTimerCallbackFunc aFunc, PRInt32 aType,
    1812                 :                              nsITimer** aTimer)
    1813                 : {
    1814                 :   // Get the delay from the look and feel service.
    1815               0 :   PRInt32 delay = LookAndFeel::GetInt(aID, 0);
    1816                 : 
    1817               0 :   nsCOMPtr<nsITimer> timer;
    1818                 : 
    1819                 :   // Create a new timer only if the delay is greater than zero.
    1820                 :   // Zero value means that this feature is completely disabled.
    1821               0 :   if (delay > 0) {
    1822               0 :     timer = do_CreateInstance("@mozilla.org/timer;1");
    1823               0 :     if (timer)
    1824               0 :       timer->InitWithFuncCallback(aFunc, this, delay, aType);
    1825                 :   }
    1826                 : 
    1827               0 :   NS_IF_ADDREF(*aTimer = timer);
    1828                 : 
    1829               0 :   return NS_OK;
    1830                 : }
    1831                 : 
    1832                 : nsresult
    1833               0 : nsTreeBodyFrame::RowCountChanged(PRInt32 aIndex, PRInt32 aCount)
    1834                 : {
    1835               0 :   if (aCount == 0 || !mView)
    1836               0 :     return NS_OK; // Nothing to do.
    1837                 : 
    1838                 : #ifdef ACCESSIBILITY
    1839               0 :   if (nsIPresShell::IsAccessibilityActive())
    1840               0 :     FireRowCountChangedEvent(aIndex, aCount);
    1841                 : #endif
    1842                 : 
    1843                 :   // Adjust our selection.
    1844               0 :   nsCOMPtr<nsITreeSelection> sel;
    1845               0 :   mView->GetSelection(getter_AddRefs(sel));
    1846               0 :   if (sel)
    1847               0 :     sel->AdjustSelection(aIndex, aCount);
    1848                 : 
    1849               0 :   if (mUpdateBatchNest)
    1850               0 :     return NS_OK;
    1851                 : 
    1852               0 :   mRowCount += aCount;
    1853                 : #ifdef DEBUG
    1854               0 :   PRInt32 rowCount = mRowCount;
    1855               0 :   mView->GetRowCount(&rowCount);
    1856               0 :   NS_ASSERTION(rowCount == mRowCount, "row count did not change by the amount suggested, check caller");
    1857                 : #endif
    1858                 : 
    1859               0 :   PRInt32 count = NS_ABS(aCount);
    1860               0 :   PRInt32 last = GetLastVisibleRow();
    1861               0 :   if (aIndex >= mTopRowIndex && aIndex <= last)
    1862               0 :     InvalidateRange(aIndex, last);
    1863                 :     
    1864               0 :   ScrollParts parts = GetScrollParts();
    1865                 : 
    1866               0 :   if (mTopRowIndex == 0) {    
    1867                 :     // Just update the scrollbar and return.
    1868               0 :     if (FullScrollbarsUpdate(false)) {
    1869               0 :       MarkDirtyIfSelect();
    1870                 :     }
    1871               0 :     return NS_OK;
    1872                 :   }
    1873                 : 
    1874               0 :   bool needsInvalidation = false;
    1875                 :   // Adjust our top row index.
    1876               0 :   if (aCount > 0) {
    1877               0 :     if (mTopRowIndex > aIndex) {
    1878                 :       // Rows came in above us.  Augment the top row index.
    1879               0 :       mTopRowIndex += aCount;
    1880                 :     }
    1881                 :   }
    1882               0 :   else if (aCount < 0) {
    1883               0 :     if (mTopRowIndex > aIndex+count-1) {
    1884                 :       // No need to invalidate. The remove happened
    1885                 :       // completely above us (offscreen).
    1886               0 :       mTopRowIndex -= count;
    1887                 :     }
    1888               0 :     else if (mTopRowIndex >= aIndex) {
    1889                 :       // This is a full-blown invalidate.
    1890               0 :       if (mTopRowIndex + mPageLength > mRowCount - 1) {
    1891               0 :         mTopRowIndex = NS_MAX(0, mRowCount - 1 - mPageLength);
    1892                 :       }
    1893               0 :       needsInvalidation = true;
    1894                 :     }
    1895                 :   }
    1896                 : 
    1897               0 :   if (FullScrollbarsUpdate(needsInvalidation)) {
    1898               0 :     MarkDirtyIfSelect();
    1899                 :   }
    1900               0 :   return NS_OK;
    1901                 : }
    1902                 : 
    1903                 : nsresult
    1904               0 : nsTreeBodyFrame::BeginUpdateBatch()
    1905                 : {
    1906               0 :   ++mUpdateBatchNest;
    1907                 : 
    1908               0 :   return NS_OK;
    1909                 : }
    1910                 : 
    1911                 : nsresult
    1912               0 : nsTreeBodyFrame::EndUpdateBatch()
    1913                 : {
    1914               0 :   NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch");
    1915                 : 
    1916               0 :   if (--mUpdateBatchNest == 0) {
    1917               0 :     if (mView) {
    1918               0 :       Invalidate();
    1919               0 :       PRInt32 countBeforeUpdate = mRowCount;
    1920               0 :       mView->GetRowCount(&mRowCount);
    1921               0 :       if (countBeforeUpdate != mRowCount) {
    1922               0 :         if (mTopRowIndex + mPageLength > mRowCount - 1) {
    1923               0 :           mTopRowIndex = NS_MAX(0, mRowCount - 1 - mPageLength);
    1924                 :         }
    1925               0 :         FullScrollbarsUpdate(false);
    1926                 :       }
    1927                 :     }
    1928                 :   }
    1929                 : 
    1930               0 :   return NS_OK;
    1931                 : }
    1932                 : 
    1933                 : void
    1934               0 : nsTreeBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, nsTreeColumn* aCol)
    1935                 : {
    1936               0 :   NS_PRECONDITION(!aCol || aCol->GetFrame(), "invalid column passed");
    1937               0 :   mScratchArray->Clear();
    1938                 :   
    1939                 :   // focus
    1940               0 :   if (mFocused)
    1941               0 :     mScratchArray->AppendElement(nsGkAtoms::focus);
    1942                 : 
    1943                 :   // sort
    1944               0 :   bool sorted = false;
    1945               0 :   mView->IsSorted(&sorted);
    1946               0 :   if (sorted)
    1947               0 :     mScratchArray->AppendElement(nsGkAtoms::sorted);
    1948                 : 
    1949                 :   // drag session
    1950               0 :   if (mSlots && mSlots->mIsDragging)
    1951               0 :     mScratchArray->AppendElement(nsGkAtoms::dragSession);
    1952                 : 
    1953               0 :   if (aRowIndex != -1) {
    1954               0 :     if (aRowIndex == mMouseOverRow)
    1955               0 :       mScratchArray->AppendElement(nsGkAtoms::hover);
    1956                 :   
    1957               0 :     nsCOMPtr<nsITreeSelection> selection;
    1958               0 :     mView->GetSelection(getter_AddRefs(selection));
    1959                 : 
    1960               0 :     if (selection) {
    1961                 :       // selected
    1962                 :       bool isSelected;
    1963               0 :       selection->IsSelected(aRowIndex, &isSelected);
    1964               0 :       if (isSelected)
    1965               0 :         mScratchArray->AppendElement(nsGkAtoms::selected);
    1966                 : 
    1967                 :       // current
    1968                 :       PRInt32 currentIndex;
    1969               0 :       selection->GetCurrentIndex(&currentIndex);
    1970               0 :       if (aRowIndex == currentIndex)
    1971               0 :         mScratchArray->AppendElement(nsGkAtoms::current);
    1972                 :   
    1973                 :       // active
    1974               0 :       if (aCol) {
    1975               0 :         nsCOMPtr<nsITreeColumn> currentColumn;
    1976               0 :         selection->GetCurrentColumn(getter_AddRefs(currentColumn));
    1977               0 :         if (aCol == currentColumn)
    1978               0 :           mScratchArray->AppendElement(nsGkAtoms::active);
    1979                 :       }
    1980                 :     }
    1981                 : 
    1982                 :     // container or leaf
    1983               0 :     bool isContainer = false;
    1984               0 :     mView->IsContainer(aRowIndex, &isContainer);
    1985               0 :     if (isContainer) {
    1986               0 :       mScratchArray->AppendElement(nsGkAtoms::container);
    1987                 : 
    1988                 :       // open or closed
    1989               0 :       bool isOpen = false;
    1990               0 :       mView->IsContainerOpen(aRowIndex, &isOpen);
    1991               0 :       if (isOpen)
    1992               0 :         mScratchArray->AppendElement(nsGkAtoms::open);
    1993                 :       else
    1994               0 :         mScratchArray->AppendElement(nsGkAtoms::closed);
    1995                 :     }
    1996                 :     else {
    1997               0 :       mScratchArray->AppendElement(nsGkAtoms::leaf);
    1998                 :     }
    1999                 : 
    2000                 :     // drop orientation
    2001               0 :     if (mSlots && mSlots->mDropAllowed && mSlots->mDropRow == aRowIndex) {
    2002               0 :       if (mSlots->mDropOrient == nsITreeView::DROP_BEFORE)
    2003               0 :         mScratchArray->AppendElement(nsGkAtoms::dropBefore);
    2004               0 :       else if (mSlots->mDropOrient == nsITreeView::DROP_ON)
    2005               0 :         mScratchArray->AppendElement(nsGkAtoms::dropOn);
    2006               0 :       else if (mSlots->mDropOrient == nsITreeView::DROP_AFTER)
    2007               0 :         mScratchArray->AppendElement(nsGkAtoms::dropAfter);
    2008                 :     }
    2009                 : 
    2010                 :     // odd or even
    2011               0 :     if (aRowIndex % 2)
    2012               0 :       mScratchArray->AppendElement(nsGkAtoms::odd);
    2013                 :     else
    2014               0 :       mScratchArray->AppendElement(nsGkAtoms::even);
    2015                 : 
    2016               0 :     nsIContent* baseContent = GetBaseElement();
    2017               0 :     if (baseContent && baseContent->HasAttr(kNameSpaceID_None, nsGkAtoms::editing))
    2018               0 :       mScratchArray->AppendElement(nsGkAtoms::editing);
    2019                 : 
    2020                 :     // multiple columns
    2021               0 :     if (mColumns->GetColumnAt(1))
    2022               0 :       mScratchArray->AppendElement(nsGkAtoms::multicol);
    2023                 :   }
    2024                 : 
    2025               0 :   if (aCol) {
    2026               0 :     mScratchArray->AppendElement(aCol->GetAtom());
    2027                 : 
    2028               0 :     if (aCol->IsPrimary())
    2029               0 :       mScratchArray->AppendElement(nsGkAtoms::primary);
    2030                 : 
    2031               0 :     if (aCol->GetType() == nsITreeColumn::TYPE_CHECKBOX) {
    2032               0 :       mScratchArray->AppendElement(nsGkAtoms::checkbox);
    2033                 : 
    2034               0 :       if (aRowIndex != -1) {
    2035               0 :         nsAutoString value;
    2036               0 :         mView->GetCellValue(aRowIndex, aCol, value);
    2037               0 :         if (value.EqualsLiteral("true"))
    2038               0 :           mScratchArray->AppendElement(nsGkAtoms::checked);
    2039                 :       }
    2040                 :     }
    2041               0 :     else if (aCol->GetType() == nsITreeColumn::TYPE_PROGRESSMETER) {
    2042               0 :       mScratchArray->AppendElement(nsGkAtoms::progressmeter);
    2043                 : 
    2044               0 :       if (aRowIndex != -1) {
    2045                 :         PRInt32 state;
    2046               0 :         mView->GetProgressMode(aRowIndex, aCol, &state);
    2047               0 :         if (state == nsITreeView::PROGRESS_NORMAL)
    2048               0 :           mScratchArray->AppendElement(nsGkAtoms::progressNormal);
    2049               0 :         else if (state == nsITreeView::PROGRESS_UNDETERMINED)
    2050               0 :           mScratchArray->AppendElement(nsGkAtoms::progressUndetermined);
    2051                 :       }
    2052                 :     }
    2053                 : 
    2054                 :     // Read special properties from attributes on the column content node
    2055               0 :     if (aCol->mContent->AttrValueIs(kNameSpaceID_None,
    2056                 :                                     nsGkAtoms::insertbefore,
    2057               0 :                                     nsGkAtoms::_true, eCaseMatters))
    2058               0 :       mScratchArray->AppendElement(nsGkAtoms::insertbefore);
    2059               0 :     if (aCol->mContent->AttrValueIs(kNameSpaceID_None,
    2060                 :                                     nsGkAtoms::insertafter,
    2061               0 :                                     nsGkAtoms::_true, eCaseMatters))
    2062               0 :       mScratchArray->AppendElement(nsGkAtoms::insertafter);
    2063                 :   }
    2064               0 : }
    2065                 : 
    2066                 : nsITheme*
    2067               0 : nsTreeBodyFrame::GetTwistyRect(PRInt32 aRowIndex,
    2068                 :                                nsTreeColumn* aColumn,
    2069                 :                                nsRect& aImageRect,
    2070                 :                                nsRect& aTwistyRect,
    2071                 :                                nsPresContext* aPresContext,
    2072                 :                                nsRenderingContext& aRenderingContext,
    2073                 :                                nsStyleContext* aTwistyContext)
    2074                 : {
    2075                 :   // The twisty rect extends all the way to the end of the cell.  This is incorrect.  We need to
    2076                 :   // determine the twisty rect's true width.  This is done by examining the style context for
    2077                 :   // a width first.  If it has one, we use that.  If it doesn't, we use the image's natural width.
    2078                 :   // If the image hasn't loaded and if no width is specified, then we just bail. If there is
    2079                 :   // a -moz-appearance involved, adjust the rect by the minimum widget size provided by
    2080                 :   // the theme implementation.
    2081               0 :   aImageRect = GetImageSize(aRowIndex, aColumn, true, aTwistyContext);
    2082               0 :   if (aImageRect.height > aTwistyRect.height)
    2083               0 :     aImageRect.height = aTwistyRect.height;
    2084               0 :   if (aImageRect.width > aTwistyRect.width)
    2085               0 :     aImageRect.width = aTwistyRect.width;
    2086                 :   else
    2087               0 :     aTwistyRect.width = aImageRect.width;
    2088                 : 
    2089               0 :   bool useTheme = false;
    2090               0 :   nsITheme *theme = nsnull;
    2091               0 :   const nsStyleDisplay* twistyDisplayData = aTwistyContext->GetStyleDisplay();
    2092               0 :   if (twistyDisplayData->mAppearance) {
    2093               0 :     theme = aPresContext->GetTheme();
    2094               0 :     if (theme && theme->ThemeSupportsWidget(aPresContext, nsnull, twistyDisplayData->mAppearance))
    2095               0 :       useTheme = true;
    2096                 :   }
    2097                 : 
    2098               0 :   if (useTheme) {
    2099               0 :     nsIntSize minTwistySizePx(0,0);
    2100               0 :     bool canOverride = true;
    2101                 :     theme->GetMinimumWidgetSize(&aRenderingContext, this, twistyDisplayData->mAppearance,
    2102               0 :                                 &minTwistySizePx, &canOverride);
    2103                 : 
    2104                 :     // GMWS() returns size in pixels, we need to convert it back to app units
    2105               0 :     nsSize minTwistySize;
    2106               0 :     minTwistySize.width = aPresContext->DevPixelsToAppUnits(minTwistySizePx.width);
    2107               0 :     minTwistySize.height = aPresContext->DevPixelsToAppUnits(minTwistySizePx.height);
    2108                 : 
    2109               0 :     if (aTwistyRect.width < minTwistySize.width || !canOverride)
    2110               0 :       aTwistyRect.width = minTwistySize.width;
    2111                 :   }
    2112                 : 
    2113               0 :   return useTheme ? theme : nsnull;
    2114                 : }
    2115                 : 
    2116                 : nsresult
    2117               0 : nsTreeBodyFrame::GetImage(PRInt32 aRowIndex, nsTreeColumn* aCol, bool aUseContext,
    2118                 :                           nsStyleContext* aStyleContext, bool& aAllowImageRegions, imgIContainer** aResult)
    2119                 : {
    2120               0 :   *aResult = nsnull;
    2121                 : 
    2122               0 :   nsAutoString imageSrc;
    2123               0 :   mView->GetImageSrc(aRowIndex, aCol, imageSrc);
    2124               0 :   nsCOMPtr<imgIRequest> styleRequest;
    2125               0 :   if (!aUseContext && !imageSrc.IsEmpty()) {
    2126               0 :     aAllowImageRegions = false;
    2127                 :   }
    2128                 :   else {
    2129                 :     // Obtain the URL from the style context.
    2130               0 :     aAllowImageRegions = true;
    2131               0 :     styleRequest = aStyleContext->GetStyleList()->GetListStyleImage();
    2132               0 :     if (!styleRequest)
    2133               0 :       return NS_OK;
    2134               0 :     nsCOMPtr<nsIURI> uri;
    2135               0 :     styleRequest->GetURI(getter_AddRefs(uri));
    2136               0 :     nsCAutoString spec;
    2137               0 :     uri->GetSpec(spec);
    2138               0 :     CopyUTF8toUTF16(spec, imageSrc);
    2139                 :   }
    2140                 : 
    2141                 :   // Look the image up in our cache.
    2142               0 :   nsTreeImageCacheEntry entry;
    2143               0 :   if (mImageCache.Get(imageSrc, &entry)) {
    2144                 :     // Find out if the image has loaded.
    2145                 :     PRUint32 status;
    2146               0 :     imgIRequest *imgReq = entry.request;
    2147               0 :     imgReq->GetImageStatus(&status);
    2148               0 :     imgReq->GetImage(aResult); // We hand back the image here.  The GetImage call addrefs *aResult.
    2149               0 :     bool animated = true; // Assuming animated is the safe option
    2150                 : 
    2151                 :     // We can only call GetAnimated if we're decoded
    2152               0 :     if (*aResult && (status & imgIRequest::STATUS_DECODE_COMPLETE))
    2153               0 :       (*aResult)->GetAnimated(&animated);
    2154                 : 
    2155               0 :     if ((!(status & imgIRequest::STATUS_LOAD_COMPLETE)) || animated) {
    2156                 :       // We either aren't done loading, or we're animating. Add our row as a listener for invalidations.
    2157               0 :       nsCOMPtr<imgIDecoderObserver> obs;
    2158               0 :       imgReq->GetDecoderObserver(getter_AddRefs(obs));
    2159                 : 
    2160               0 :       if (obs) {
    2161               0 :         static_cast<nsTreeImageListener*> (obs.get())->AddCell(aRowIndex, aCol);
    2162                 :       }
    2163                 : 
    2164               0 :       return NS_OK;
    2165                 :     }
    2166                 :   }
    2167                 : 
    2168               0 :   if (!*aResult) {
    2169                 :     // Create a new nsTreeImageListener object and pass it our row and column
    2170                 :     // information.
    2171               0 :     nsTreeImageListener* listener = new nsTreeImageListener(this);
    2172               0 :     if (!listener)
    2173               0 :       return NS_ERROR_OUT_OF_MEMORY;
    2174                 : 
    2175               0 :     if (!mCreatedListeners.PutEntry(listener)) {
    2176               0 :       return NS_ERROR_FAILURE;
    2177                 :     }
    2178                 : 
    2179               0 :     listener->AddCell(aRowIndex, aCol);
    2180               0 :     nsCOMPtr<imgIDecoderObserver> imgDecoderObserver = listener;
    2181                 : 
    2182               0 :     nsCOMPtr<imgIRequest> imageRequest;
    2183               0 :     if (styleRequest) {
    2184               0 :       styleRequest->Clone(imgDecoderObserver, getter_AddRefs(imageRequest));
    2185                 :     } else {
    2186               0 :       nsIDocument* doc = mContent->GetDocument();
    2187               0 :       if (!doc)
    2188                 :         // The page is currently being torn down.  Why bother.
    2189               0 :         return NS_ERROR_FAILURE;
    2190                 : 
    2191               0 :       nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
    2192                 : 
    2193               0 :       nsCOMPtr<nsIURI> srcURI;
    2194               0 :       nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(srcURI),
    2195                 :                                                 imageSrc,
    2196                 :                                                 doc,
    2197               0 :                                                 baseURI);
    2198               0 :       if (!srcURI)
    2199               0 :         return NS_ERROR_FAILURE;
    2200                 : 
    2201                 :       // XXXbz what's the origin principal for this stuff that comes from our
    2202                 :       // view?  I guess we should assume that it's the node's principal...
    2203               0 :       if (nsContentUtils::CanLoadImage(srcURI, mContent, doc,
    2204               0 :                                        mContent->NodePrincipal())) {
    2205                 :         nsresult rv = nsContentUtils::LoadImage(srcURI,
    2206                 :                                                 doc,
    2207                 :                                                 mContent->NodePrincipal(),
    2208                 :                                                 doc->GetDocumentURI(),
    2209                 :                                                 imgDecoderObserver,
    2210                 :                                                 nsIRequest::LOAD_NORMAL,
    2211               0 :                                                 getter_AddRefs(imageRequest));
    2212               0 :         NS_ENSURE_SUCCESS(rv, rv);
    2213                 :                                   
    2214                 :       }
    2215                 :     }
    2216               0 :     listener->UnsuppressInvalidation();
    2217                 : 
    2218               0 :     if (!imageRequest)
    2219               0 :       return NS_ERROR_FAILURE;
    2220                 : 
    2221                 :     // We don't want discarding/decode-on-draw for xul images
    2222               0 :     imageRequest->RequestDecode();
    2223               0 :     imageRequest->LockImage();
    2224                 : 
    2225                 :     // In a case it was already cached.
    2226               0 :     imageRequest->GetImage(aResult);
    2227               0 :     nsTreeImageCacheEntry cacheEntry(imageRequest, imgDecoderObserver);
    2228               0 :     mImageCache.Put(imageSrc, cacheEntry);
    2229                 :   }
    2230               0 :   return NS_OK;
    2231                 : }
    2232                 : 
    2233               0 : nsRect nsTreeBodyFrame::GetImageSize(PRInt32 aRowIndex, nsTreeColumn* aCol, bool aUseContext,
    2234                 :                                      nsStyleContext* aStyleContext)
    2235                 : {
    2236                 :   // XXX We should respond to visibility rules for collapsed vs. hidden.
    2237                 : 
    2238                 :   // This method returns the width of the twisty INCLUDING borders and padding.
    2239                 :   // It first checks the style context for a width.  If none is found, it tries to
    2240                 :   // use the default image width for the twisty.  If no image is found, it defaults
    2241                 :   // to border+padding.
    2242               0 :   nsRect r(0,0,0,0);
    2243               0 :   nsMargin bp(0,0,0,0);
    2244               0 :   GetBorderPadding(aStyleContext, bp);
    2245               0 :   r.Inflate(bp);
    2246                 : 
    2247                 :   // Now r contains our border+padding info.  We now need to get our width and
    2248                 :   // height.
    2249               0 :   bool needWidth = false;
    2250               0 :   bool needHeight = false;
    2251                 : 
    2252                 :   // We have to load image even though we already have a size.
    2253                 :   // Don't change this, otherwise things start to go crazy.
    2254               0 :   bool useImageRegion = true;
    2255               0 :   nsCOMPtr<imgIContainer> image;
    2256               0 :   GetImage(aRowIndex, aCol, aUseContext, aStyleContext, useImageRegion, getter_AddRefs(image));
    2257                 : 
    2258               0 :   const nsStylePosition* myPosition = aStyleContext->GetStylePosition();
    2259               0 :   const nsStyleList* myList = aStyleContext->GetStyleList();
    2260                 : 
    2261               0 :   if (useImageRegion) {
    2262               0 :     r.x += myList->mImageRegion.x;
    2263               0 :     r.y += myList->mImageRegion.y;
    2264                 :   }
    2265                 : 
    2266               0 :   if (myPosition->mWidth.GetUnit() == eStyleUnit_Coord)  {
    2267               0 :     PRInt32 val = myPosition->mWidth.GetCoordValue();
    2268               0 :     r.width += val;
    2269                 :   }
    2270               0 :   else if (useImageRegion && myList->mImageRegion.width > 0)
    2271               0 :     r.width += myList->mImageRegion.width;
    2272                 :   else 
    2273               0 :     needWidth = true;
    2274                 : 
    2275               0 :   if (myPosition->mHeight.GetUnit() == eStyleUnit_Coord)  {
    2276               0 :     PRInt32 val = myPosition->mHeight.GetCoordValue();
    2277               0 :     r.height += val;
    2278                 :   }
    2279               0 :   else if (useImageRegion && myList->mImageRegion.height > 0)
    2280               0 :     r.height += myList->mImageRegion.height;
    2281                 :   else 
    2282               0 :     needHeight = true;
    2283                 : 
    2284               0 :   if (image) {
    2285               0 :     if (needWidth || needHeight) {
    2286                 :       // Get the natural image size.
    2287                 : 
    2288               0 :       if (needWidth) {
    2289                 :         // Get the size from the image.
    2290                 :         nscoord width;
    2291               0 :         image->GetWidth(&width);
    2292               0 :         r.width += nsPresContext::CSSPixelsToAppUnits(width); 
    2293                 :       }
    2294                 :     
    2295               0 :       if (needHeight) {
    2296                 :         nscoord height;
    2297               0 :         image->GetHeight(&height);
    2298               0 :         r.height += nsPresContext::CSSPixelsToAppUnits(height); 
    2299                 :       }
    2300                 :     }
    2301                 :   }
    2302                 : 
    2303                 :   return r;
    2304                 : }
    2305                 : 
    2306                 : // GetImageDestSize returns the destination size of the image.
    2307                 : // The width and height do not include borders and padding.
    2308                 : // The width and height have not been adjusted to fit in the row height
    2309                 : // or cell width.
    2310                 : // The width and height reflect the destination size specified in CSS,
    2311                 : // or the image region specified in CSS, or the natural size of the
    2312                 : // image.
    2313                 : // If only the destination width has been specified in CSS, the height is
    2314                 : // calculated to maintain the aspect ratio of the image.
    2315                 : // If only the destination height has been specified in CSS, the width is
    2316                 : // calculated to maintain the aspect ratio of the image.
    2317                 : nsSize
    2318               0 : nsTreeBodyFrame::GetImageDestSize(nsStyleContext* aStyleContext,
    2319                 :                                   bool useImageRegion,
    2320                 :                                   imgIContainer* image)
    2321                 : {
    2322               0 :   nsSize size(0,0);
    2323                 : 
    2324                 :   // We need to get the width and height.
    2325               0 :   bool needWidth = false;
    2326               0 :   bool needHeight = false;
    2327                 : 
    2328                 :   // Get the style position to see if the CSS has specified the
    2329                 :   // destination width/height.
    2330               0 :   const nsStylePosition* myPosition = aStyleContext->GetStylePosition();
    2331                 : 
    2332               0 :   if (myPosition->mWidth.GetUnit() == eStyleUnit_Coord) {
    2333                 :     // CSS has specified the destination width.
    2334               0 :     size.width = myPosition->mWidth.GetCoordValue();
    2335                 :   }
    2336                 :   else {
    2337                 :     // We'll need to get the width of the image/region.
    2338               0 :     needWidth = true;
    2339                 :   }
    2340                 : 
    2341               0 :   if (myPosition->mHeight.GetUnit() == eStyleUnit_Coord)  {
    2342                 :     // CSS has specified the destination height.
    2343               0 :     size.height = myPosition->mHeight.GetCoordValue();
    2344                 :   }
    2345                 :   else {
    2346                 :     // We'll need to get the height of the image/region.
    2347               0 :     needHeight = true;
    2348                 :   }
    2349                 : 
    2350               0 :   if (needWidth || needHeight) {
    2351                 :     // We need to get the size of the image/region.
    2352               0 :     nsSize imageSize(0,0);
    2353                 : 
    2354               0 :     const nsStyleList* myList = aStyleContext->GetStyleList();
    2355                 : 
    2356               0 :     if (useImageRegion && myList->mImageRegion.width > 0) {
    2357                 :       // CSS has specified an image region.
    2358                 :       // Use the width of the image region.
    2359               0 :       imageSize.width = myList->mImageRegion.width;
    2360                 :     }
    2361               0 :     else if (image) {
    2362                 :       nscoord width;
    2363               0 :       image->GetWidth(&width);
    2364               0 :       imageSize.width = nsPresContext::CSSPixelsToAppUnits(width);
    2365                 :     }
    2366                 : 
    2367               0 :     if (useImageRegion && myList->mImageRegion.height > 0) {
    2368                 :       // CSS has specified an image region.
    2369                 :       // Use the height of the image region.
    2370               0 :       imageSize.height = myList->mImageRegion.height;
    2371                 :     }
    2372               0 :     else if (image) {
    2373                 :       nscoord height;
    2374               0 :       image->GetHeight(&height);
    2375               0 :       imageSize.height = nsPresContext::CSSPixelsToAppUnits(height);
    2376                 :     }
    2377                 : 
    2378               0 :     if (needWidth) {
    2379               0 :       if (!needHeight && imageSize.height != 0) {
    2380                 :         // The CSS specified the destination height, but not the destination
    2381                 :         // width. We need to calculate the width so that we maintain the
    2382                 :         // image's aspect ratio.
    2383               0 :         size.width = imageSize.width * size.height / imageSize.height;
    2384                 :       }
    2385                 :       else {
    2386               0 :         size.width = imageSize.width;
    2387                 :       }
    2388                 :     }
    2389                 : 
    2390               0 :     if (needHeight) {
    2391               0 :       if (!needWidth && imageSize.width != 0) {
    2392                 :         // The CSS specified the destination width, but not the destination
    2393                 :         // height. We need to calculate the height so that we maintain the
    2394                 :         // image's aspect ratio.
    2395               0 :         size.height = imageSize.height * size.width / imageSize.width;
    2396                 :       }
    2397                 :       else {
    2398               0 :         size.height = imageSize.height;
    2399                 :       }
    2400                 :     }
    2401                 :   }
    2402                 : 
    2403                 :   return size;
    2404                 : }
    2405                 : 
    2406                 : // GetImageSourceRect returns the source rectangle of the image to be
    2407                 : // displayed.
    2408                 : // The width and height reflect the image region specified in CSS, or
    2409                 : // the natural size of the image.
    2410                 : // The width and height do not include borders and padding.
    2411                 : // The width and height do not reflect the destination size specified
    2412                 : // in CSS.
    2413                 : nsRect
    2414               0 : nsTreeBodyFrame::GetImageSourceRect(nsStyleContext* aStyleContext,
    2415                 :                                     bool useImageRegion,
    2416                 :                                     imgIContainer* image)
    2417                 : {
    2418               0 :   nsRect r(0,0,0,0);
    2419                 : 
    2420               0 :   const nsStyleList* myList = aStyleContext->GetStyleList();
    2421                 : 
    2422               0 :   if (useImageRegion &&
    2423                 :       (myList->mImageRegion.width > 0 || myList->mImageRegion.height > 0)) {
    2424                 :     // CSS has specified an image region.
    2425               0 :     r = myList->mImageRegion;
    2426                 :   }
    2427               0 :   else if (image) {
    2428                 :     // Use the actual image size.
    2429                 :     nscoord coord;
    2430               0 :     image->GetWidth(&coord);
    2431               0 :     r.width = nsPresContext::CSSPixelsToAppUnits(coord);
    2432               0 :     image->GetHeight(&coord);
    2433               0 :     r.height = nsPresContext::CSSPixelsToAppUnits(coord);
    2434                 :   }
    2435                 : 
    2436                 :   return r;
    2437                 : }
    2438                 : 
    2439               0 : PRInt32 nsTreeBodyFrame::GetRowHeight()
    2440                 : {
    2441                 :   // Look up the correct height.  It is equal to the specified height
    2442                 :   // + the specified margins.
    2443               0 :   mScratchArray->Clear();
    2444               0 :   nsStyleContext* rowContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreerow);
    2445               0 :   if (rowContext) {
    2446               0 :     const nsStylePosition* myPosition = rowContext->GetStylePosition();
    2447                 : 
    2448               0 :     nscoord minHeight = 0;
    2449               0 :     if (myPosition->mMinHeight.GetUnit() == eStyleUnit_Coord)
    2450               0 :       minHeight = myPosition->mMinHeight.GetCoordValue();
    2451                 : 
    2452               0 :     nscoord height = 0;
    2453               0 :     if (myPosition->mHeight.GetUnit() == eStyleUnit_Coord)
    2454               0 :       height = myPosition->mHeight.GetCoordValue();
    2455                 : 
    2456               0 :     if (height < minHeight)
    2457               0 :       height = minHeight;
    2458                 : 
    2459               0 :     if (height > 0) {
    2460               0 :       height = nsPresContext::AppUnitsToIntCSSPixels(height);
    2461               0 :       height += height % 2;
    2462               0 :       height = nsPresContext::CSSPixelsToAppUnits(height);
    2463                 : 
    2464                 :       // XXX Check box-sizing to determine if border/padding should augment the height
    2465                 :       // Inflate the height by our margins.
    2466               0 :       nsRect rowRect(0,0,0,height);
    2467               0 :       nsMargin rowMargin;
    2468               0 :       rowContext->GetStyleMargin()->GetMargin(rowMargin);
    2469               0 :       rowRect.Inflate(rowMargin);
    2470               0 :       height = rowRect.height;
    2471               0 :       return height;
    2472                 :     }
    2473                 :   }
    2474                 : 
    2475               0 :   return nsPresContext::CSSPixelsToAppUnits(18); // As good a default as any.
    2476                 : }
    2477                 : 
    2478               0 : PRInt32 nsTreeBodyFrame::GetIndentation()
    2479                 : {
    2480                 :   // Look up the correct indentation.  It is equal to the specified indentation width.
    2481               0 :   mScratchArray->Clear();
    2482               0 :   nsStyleContext* indentContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeindentation);
    2483               0 :   if (indentContext) {
    2484               0 :     const nsStylePosition* myPosition = indentContext->GetStylePosition();
    2485               0 :     if (myPosition->mWidth.GetUnit() == eStyleUnit_Coord)  {
    2486               0 :       nscoord val = myPosition->mWidth.GetCoordValue();
    2487               0 :       return val;
    2488                 :     }
    2489                 :   }
    2490                 : 
    2491               0 :   return nsPresContext::CSSPixelsToAppUnits(16); // As good a default as any.
    2492                 : }
    2493                 : 
    2494               0 : void nsTreeBodyFrame::CalcInnerBox()
    2495                 : {
    2496               0 :   mInnerBox.SetRect(0, 0, mRect.width, mRect.height);
    2497               0 :   AdjustForBorderPadding(mStyleContext, mInnerBox);
    2498               0 : }
    2499                 : 
    2500                 : nscoord
    2501               0 : nsTreeBodyFrame::CalcHorzWidth(const ScrollParts& aParts)
    2502                 : {
    2503                 :   // Compute the adjustment to the last column. This varies depending on the
    2504                 :   // visibility of the columnpicker and the scrollbar.
    2505               0 :   if (aParts.mColumnsFrame)
    2506               0 :     mAdjustWidth = mRect.width - aParts.mColumnsFrame->GetRect().width;
    2507                 :   else
    2508               0 :     mAdjustWidth = 0;
    2509                 : 
    2510               0 :   nscoord width = 0;
    2511                 : 
    2512                 :   // We calculate this from the scrollable frame, so that it 
    2513                 :   // properly covers all contingencies of what could be 
    2514                 :   // scrollable (columns, body, etc...)
    2515                 : 
    2516               0 :   if (aParts.mColumnsScrollFrame) {
    2517               0 :     width = aParts.mColumnsScrollFrame->GetScrollRange().width +
    2518               0 :       aParts.mColumnsScrollFrame->GetScrollPortRect().width;
    2519                 :   }
    2520                 : 
    2521                 :   // If no horz scrolling periphery is present, then just return our width
    2522               0 :   if (width == 0)
    2523               0 :     width = mRect.width;
    2524                 : 
    2525               0 :   return width;
    2526                 : }
    2527                 : 
    2528                 : NS_IMETHODIMP
    2529               0 : nsTreeBodyFrame::GetCursor(const nsPoint& aPoint,
    2530                 :                            nsIFrame::Cursor& aCursor)
    2531                 : {
    2532                 :   // Check the GetScriptHandlingObject so we don't end up running code when
    2533                 :   // the document is a zombie.
    2534                 :   bool dummy;
    2535               0 :   if (mView && GetContent()->GetCurrentDoc()->GetScriptHandlingObject(dummy)) {
    2536                 :     PRInt32 row;
    2537                 :     nsTreeColumn* col;
    2538                 :     nsIAtom* child;
    2539               0 :     GetCellAt(aPoint.x, aPoint.y, &row, &col, &child);
    2540                 : 
    2541               0 :     if (child) {
    2542                 :       // Our scratch array is already prefilled.
    2543               0 :       nsStyleContext* childContext = GetPseudoStyleContext(child);
    2544                 : 
    2545                 :       FillCursorInformationFromStyle(childContext->GetStyleUserInterface(),
    2546               0 :                                      aCursor);
    2547               0 :       if (aCursor.mCursor == NS_STYLE_CURSOR_AUTO)
    2548               0 :         aCursor.mCursor = NS_STYLE_CURSOR_DEFAULT;
    2549                 : 
    2550               0 :       return NS_OK;
    2551                 :     }
    2552                 :   }
    2553                 : 
    2554               0 :   return nsLeafBoxFrame::GetCursor(aPoint, aCursor);
    2555                 : }
    2556                 : 
    2557               0 : static PRUint32 GetDropEffect(nsGUIEvent* aEvent)
    2558                 : {
    2559               0 :   NS_ASSERTION(aEvent->eventStructType == NS_DRAG_EVENT, "wrong event type");
    2560               0 :   nsDragEvent* dragEvent = static_cast<nsDragEvent *>(aEvent);
    2561               0 :   nsContentUtils::SetDataTransferInEvent(dragEvent);
    2562                 : 
    2563               0 :   PRUint32 action = 0;
    2564               0 :   if (dragEvent->dataTransfer)
    2565               0 :     dragEvent->dataTransfer->GetDropEffectInt(&action);
    2566               0 :   return action;
    2567                 : }
    2568                 : 
    2569                 : NS_IMETHODIMP
    2570               0 : nsTreeBodyFrame::HandleEvent(nsPresContext* aPresContext,
    2571                 :                              nsGUIEvent* aEvent,
    2572                 :                              nsEventStatus* aEventStatus)
    2573                 : {
    2574               0 :   if (aEvent->message == NS_MOUSE_ENTER_SYNTH || aEvent->message == NS_MOUSE_MOVE) {
    2575               0 :     nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
    2576               0 :     PRInt32 xTwips = pt.x - mInnerBox.x;
    2577               0 :     PRInt32 yTwips = pt.y - mInnerBox.y;
    2578               0 :     PRInt32 newrow = GetRowAt(xTwips, yTwips);
    2579               0 :     if (mMouseOverRow != newrow) {
    2580                 :       // redraw the old and the new row
    2581               0 :       if (mMouseOverRow != -1)
    2582               0 :         InvalidateRow(mMouseOverRow);
    2583               0 :       mMouseOverRow = newrow;
    2584               0 :       if (mMouseOverRow != -1)
    2585               0 :         InvalidateRow(mMouseOverRow);
    2586               0 :     }
    2587                 :   }
    2588               0 :   else if (aEvent->message == NS_MOUSE_EXIT_SYNTH) {
    2589               0 :     if (mMouseOverRow != -1) {
    2590               0 :       InvalidateRow(mMouseOverRow);
    2591               0 :       mMouseOverRow = -1;
    2592                 :     }
    2593                 :   }
    2594               0 :   else if (aEvent->message == NS_DRAGDROP_ENTER) {
    2595               0 :     if (!mSlots)
    2596               0 :       mSlots = new Slots();
    2597                 : 
    2598                 :     // Cache several things we'll need throughout the course of our work. These
    2599                 :     // will all get released on a drag exit.
    2600                 : 
    2601               0 :     if (mSlots->mTimer) {
    2602               0 :       mSlots->mTimer->Cancel();
    2603               0 :       mSlots->mTimer = nsnull;
    2604                 :     }
    2605                 : 
    2606                 :     // Cache the drag session.
    2607               0 :     mSlots->mIsDragging = true;
    2608               0 :     mSlots->mDropRow = -1;
    2609               0 :     mSlots->mDropOrient = -1;
    2610               0 :     mSlots->mDragAction = GetDropEffect(aEvent);
    2611                 :   }
    2612               0 :   else if (aEvent->message == NS_DRAGDROP_OVER) {
    2613                 :     // The mouse is hovering over this tree. If we determine things are
    2614                 :     // different from the last time, invalidate the drop feedback at the old
    2615                 :     // position, query the view to see if the current location is droppable,
    2616                 :     // and then invalidate the drop feedback at the new location if it is.
    2617                 :     // The mouse may or may not have changed position from the last time
    2618                 :     // we were called, so optimize out a lot of the extra notifications by
    2619                 :     // checking if anything changed first. For drop feedback we use drop,
    2620                 :     // dropBefore and dropAfter property.
    2621                 : 
    2622               0 :     if (!mView || !mSlots)
    2623               0 :       return NS_OK;
    2624                 : 
    2625                 :     // Save last values, we will need them.
    2626               0 :     PRInt32 lastDropRow = mSlots->mDropRow;
    2627               0 :     PRInt16 lastDropOrient = mSlots->mDropOrient;
    2628                 : #ifndef XP_MACOSX
    2629               0 :     PRInt16 lastScrollLines = mSlots->mScrollLines;
    2630                 : #endif
    2631                 : 
    2632                 :     // Find out the current drag action
    2633               0 :     PRUint32 lastDragAction = mSlots->mDragAction;
    2634               0 :     mSlots->mDragAction = GetDropEffect(aEvent);
    2635                 : 
    2636                 :     // Compute the row mouse is over and the above/below/on state.
    2637                 :     // Below we'll use this to see if anything changed.
    2638                 :     // Also check if we want to auto-scroll.
    2639               0 :     ComputeDropPosition(aEvent, &mSlots->mDropRow, &mSlots->mDropOrient, &mSlots->mScrollLines);
    2640                 : 
    2641                 :     // While we're here, handle tracking of scrolling during a drag.
    2642               0 :     if (mSlots->mScrollLines) {
    2643               0 :       if (mSlots->mDropAllowed) {
    2644                 :         // Invalidate primary cell at old location.
    2645               0 :         mSlots->mDropAllowed = false;
    2646               0 :         InvalidateDropFeedback(lastDropRow, lastDropOrient);
    2647                 :       }
    2648                 : #ifdef XP_MACOSX
    2649                 :       ScrollByLines(mSlots->mScrollLines);
    2650                 : #else
    2651               0 :       if (!lastScrollLines) {
    2652                 :         // Cancel any previously initialized timer.
    2653               0 :         if (mSlots->mTimer) {
    2654               0 :           mSlots->mTimer->Cancel();
    2655               0 :           mSlots->mTimer = nsnull;
    2656                 :         }
    2657                 : 
    2658                 :         // Set a timer to trigger the tree scrolling.
    2659                 :         CreateTimer(LookAndFeel::eIntID_TreeLazyScrollDelay,
    2660                 :                     LazyScrollCallback, nsITimer::TYPE_ONE_SHOT,
    2661               0 :                     getter_AddRefs(mSlots->mTimer));
    2662                 :        }
    2663                 : #endif
    2664                 :       // Bail out to prevent spring loaded timer and feedback line settings.
    2665               0 :       return NS_OK;
    2666                 :     }
    2667                 : 
    2668                 :     // If changed from last time, invalidate primary cell at the old location and if allowed, 
    2669                 :     // invalidate primary cell at the new location. If nothing changed, just bail.
    2670               0 :     if (mSlots->mDropRow != lastDropRow ||
    2671                 :         mSlots->mDropOrient != lastDropOrient ||
    2672                 :         mSlots->mDragAction != lastDragAction) {
    2673                 : 
    2674                 :       // Invalidate row at the old location.
    2675               0 :       if (mSlots->mDropAllowed) {
    2676               0 :         mSlots->mDropAllowed = false;
    2677               0 :         InvalidateDropFeedback(lastDropRow, lastDropOrient);
    2678                 :       }
    2679                 : 
    2680               0 :       if (mSlots->mTimer) {
    2681                 :         // Timer is active but for a different row than the current one, kill it.
    2682               0 :         mSlots->mTimer->Cancel();
    2683               0 :         mSlots->mTimer = nsnull;
    2684                 :       }
    2685                 : 
    2686               0 :       if (mSlots->mDropRow >= 0) {
    2687               0 :         if (!mSlots->mTimer && mSlots->mDropOrient == nsITreeView::DROP_ON) {
    2688                 :           // Either there wasn't a timer running or it was just killed above.
    2689                 :           // If over a folder, start up a timer to open the folder.
    2690               0 :           bool isContainer = false;
    2691               0 :           mView->IsContainer(mSlots->mDropRow, &isContainer);
    2692               0 :           if (isContainer) {
    2693               0 :             bool isOpen = false;
    2694               0 :             mView->IsContainerOpen(mSlots->mDropRow, &isOpen);
    2695               0 :             if (!isOpen) {
    2696                 :               // This node isn't expanded, set a timer to expand it.
    2697                 :               CreateTimer(LookAndFeel::eIntID_TreeOpenDelay,
    2698                 :                           OpenCallback, nsITimer::TYPE_ONE_SHOT,
    2699               0 :                           getter_AddRefs(mSlots->mTimer));
    2700                 :             }
    2701                 :           }
    2702                 :         }
    2703                 : 
    2704                 :         // The dataTransfer was initialized by the call to GetDropEffect above.
    2705               0 :         bool canDropAtNewLocation = false;
    2706               0 :         nsDragEvent* dragEvent = static_cast<nsDragEvent *>(aEvent);
    2707               0 :         mView->CanDrop(mSlots->mDropRow, mSlots->mDropOrient,
    2708               0 :                        dragEvent->dataTransfer, &canDropAtNewLocation);
    2709                 : 
    2710               0 :         if (canDropAtNewLocation) {
    2711                 :           // Invalidate row at the new location.
    2712               0 :           mSlots->mDropAllowed = canDropAtNewLocation;
    2713               0 :           InvalidateDropFeedback(mSlots->mDropRow, mSlots->mDropOrient);
    2714                 :         }
    2715                 :       }
    2716                 :     }
    2717                 : 
    2718                 :     // Indicate that the drop is allowed by preventing the default behaviour.
    2719               0 :     if (mSlots->mDropAllowed)
    2720               0 :       *aEventStatus = nsEventStatus_eConsumeNoDefault;
    2721                 :   }
    2722               0 :   else if (aEvent->message == NS_DRAGDROP_DROP) {
    2723                 :      // this event was meant for another frame, so ignore it
    2724               0 :      if (!mSlots)
    2725               0 :        return NS_OK;
    2726                 : 
    2727                 :     // Tell the view where the drop happened.
    2728                 : 
    2729                 :     // Remove the drop folder and all its parents from the array.
    2730                 :     PRInt32 parentIndex;
    2731               0 :     nsresult rv = mView->GetParentIndex(mSlots->mDropRow, &parentIndex);
    2732               0 :     while (NS_SUCCEEDED(rv) && parentIndex >= 0) {
    2733               0 :       mSlots->mArray.RemoveElement(parentIndex);
    2734               0 :       rv = mView->GetParentIndex(parentIndex, &parentIndex);
    2735                 :     }
    2736                 : 
    2737               0 :     NS_ASSERTION(aEvent->eventStructType == NS_DRAG_EVENT, "wrong event type");
    2738               0 :     nsDragEvent* dragEvent = static_cast<nsDragEvent*>(aEvent);
    2739               0 :     nsContentUtils::SetDataTransferInEvent(dragEvent);
    2740                 : 
    2741               0 :     mView->Drop(mSlots->mDropRow, mSlots->mDropOrient, dragEvent->dataTransfer);
    2742               0 :     mSlots->mDropRow = -1;
    2743               0 :     mSlots->mDropOrient = -1;
    2744               0 :     mSlots->mIsDragging = false;
    2745               0 :     *aEventStatus = nsEventStatus_eConsumeNoDefault; // already handled the drop
    2746                 :   }
    2747               0 :   else if (aEvent->message == NS_DRAGDROP_EXIT) {
    2748                 :     // this event was meant for another frame, so ignore it
    2749               0 :     if (!mSlots)
    2750               0 :       return NS_OK;
    2751                 : 
    2752                 :     // Clear out all our tracking vars.
    2753                 : 
    2754               0 :     if (mSlots->mDropAllowed) {
    2755               0 :       mSlots->mDropAllowed = false;
    2756               0 :       InvalidateDropFeedback(mSlots->mDropRow, mSlots->mDropOrient);
    2757                 :     }
    2758                 :     else
    2759               0 :       mSlots->mDropAllowed = false;
    2760               0 :     mSlots->mIsDragging = false;
    2761               0 :     mSlots->mScrollLines = 0;
    2762                 :     // If a drop is occuring, the exit event will fire just before the drop
    2763                 :     // event, so don't reset mDropRow or mDropOrient as these fields are used
    2764                 :     // by the drop event.
    2765               0 :     if (mSlots->mTimer) {
    2766               0 :       mSlots->mTimer->Cancel();
    2767               0 :       mSlots->mTimer = nsnull;
    2768                 :     }
    2769                 : 
    2770               0 :     if (!mSlots->mArray.IsEmpty()) {
    2771                 :       // Close all spring loaded folders except the drop folder.
    2772                 :       CreateTimer(LookAndFeel::eIntID_TreeCloseDelay,
    2773                 :                   CloseCallback, nsITimer::TYPE_ONE_SHOT,
    2774               0 :                   getter_AddRefs(mSlots->mTimer));
    2775                 :     }
    2776                 :   }
    2777                 : 
    2778               0 :   return NS_OK;
    2779                 : }
    2780                 : 
    2781                 : static nsLineStyle
    2782               0 : ConvertBorderStyleToLineStyle(PRUint8 aBorderStyle)
    2783                 : {
    2784               0 :   switch (aBorderStyle) {
    2785                 :     case NS_STYLE_BORDER_STYLE_DOTTED:
    2786               0 :       return nsLineStyle_kDotted;
    2787                 :     case NS_STYLE_BORDER_STYLE_DASHED:
    2788               0 :       return nsLineStyle_kDashed;
    2789                 :     default:
    2790               0 :       return nsLineStyle_kSolid;
    2791                 :   }
    2792                 : }
    2793                 : 
    2794                 : static void
    2795               0 : PaintTreeBody(nsIFrame* aFrame, nsRenderingContext* aCtx,
    2796                 :               const nsRect& aDirtyRect, nsPoint aPt)
    2797                 : {
    2798               0 :   static_cast<nsTreeBodyFrame*>(aFrame)->PaintTreeBody(*aCtx, aDirtyRect, aPt);
    2799               0 : }
    2800                 : 
    2801                 : // Painting routines
    2802                 : NS_IMETHODIMP
    2803               0 : nsTreeBodyFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    2804                 :                                   const nsRect&           aDirtyRect,
    2805                 :                                   const nsDisplayListSet& aLists)
    2806                 : {
    2807                 :   // REVIEW: why did we paint if we were collapsed? that makes no sense!
    2808               0 :   if (!IsVisibleForPainting(aBuilder))
    2809               0 :     return NS_OK; // We're invisible.  Don't paint.
    2810                 : 
    2811                 :   // Handles painting our background, border, and outline.
    2812               0 :   nsresult rv = nsLeafBoxFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
    2813               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2814                 : 
    2815                 :   // Bail out now if there's no view or we can't run script because the
    2816                 :   // document is a zombie
    2817               0 :   if (!mView || !GetContent()->GetCurrentDoc()->GetScriptGlobalObject())
    2818               0 :     return NS_OK;
    2819                 : 
    2820                 :   return aLists.Content()->AppendNewToTop(new (aBuilder)
    2821                 :       nsDisplayGeneric(aBuilder, this, ::PaintTreeBody, "XULTreeBody",
    2822               0 :                        nsDisplayItem::TYPE_XUL_TREE_BODY));
    2823                 : }
    2824                 : 
    2825                 : void
    2826               0 : nsTreeBodyFrame::PaintTreeBody(nsRenderingContext& aRenderingContext,
    2827                 :                                const nsRect& aDirtyRect, nsPoint aPt)
    2828                 : {
    2829                 :   // Update our available height and our page count.
    2830               0 :   CalcInnerBox();
    2831               0 :   aRenderingContext.PushState();
    2832               0 :   aRenderingContext.IntersectClip(mInnerBox + aPt);
    2833               0 :   PRInt32 oldPageCount = mPageLength;
    2834               0 :   if (!mHasFixedRowCount)
    2835               0 :     mPageLength = mInnerBox.height/mRowHeight;
    2836                 : 
    2837               0 :   if (oldPageCount != mPageLength || mHorzWidth != CalcHorzWidth(GetScrollParts())) {
    2838                 :     // Schedule a ResizeReflow that will update our info properly.
    2839               0 :     PresContext()->PresShell()->
    2840               0 :       FrameNeedsReflow(this, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
    2841                 :   }
    2842                 : #ifdef DEBUG
    2843               0 :   PRInt32 rowCount = mRowCount;
    2844               0 :   mView->GetRowCount(&rowCount);
    2845               0 :   NS_WARN_IF_FALSE(mRowCount == rowCount, "row count changed unexpectedly");
    2846                 : #endif
    2847                 : 
    2848                 :   // Loop through our columns and paint them (e.g., for sorting).  This is only
    2849                 :   // relevant when painting backgrounds, since columns contain no content.  Content
    2850                 :   // is contained in the rows.
    2851               0 :   for (nsTreeColumn* currCol = mColumns->GetFirstColumn(); currCol;
    2852                 :        currCol = currCol->GetNext()) {
    2853               0 :     nsRect colRect;
    2854                 :     nsresult rv = currCol->GetRect(this, mInnerBox.y, mInnerBox.height,
    2855               0 :                                    &colRect);
    2856                 :     // Don't paint hidden columns.
    2857               0 :     if (NS_FAILED(rv) || colRect.width == 0) continue;
    2858                 : 
    2859               0 :     if (OffsetForHorzScroll(colRect, false)) {
    2860               0 :       nsRect dirtyRect;
    2861               0 :       colRect += aPt;
    2862               0 :       if (dirtyRect.IntersectRect(aDirtyRect, colRect)) {
    2863               0 :         PaintColumn(currCol, colRect, PresContext(), aRenderingContext, aDirtyRect);
    2864                 :       }
    2865                 :     }
    2866                 :   }
    2867                 :   // Loop through our on-screen rows.
    2868               0 :   for (PRInt32 i = mTopRowIndex; i < mRowCount && i <= mTopRowIndex+mPageLength; i++) {
    2869               0 :     nsRect rowRect(mInnerBox.x, mInnerBox.y+mRowHeight*(i-mTopRowIndex), mInnerBox.width, mRowHeight);
    2870               0 :     nsRect dirtyRect;
    2871               0 :     if (dirtyRect.IntersectRect(aDirtyRect, rowRect + aPt) &&
    2872                 :         rowRect.y < (mInnerBox.y+mInnerBox.height)) {
    2873               0 :       PaintRow(i, rowRect + aPt, PresContext(), aRenderingContext, aDirtyRect, aPt);
    2874                 :     }
    2875                 :   }
    2876                 : 
    2877               0 :   if (mSlots && mSlots->mDropAllowed && (mSlots->mDropOrient == nsITreeView::DROP_BEFORE ||
    2878                 :       mSlots->mDropOrient == nsITreeView::DROP_AFTER)) {
    2879               0 :     nscoord yPos = mInnerBox.y + mRowHeight * (mSlots->mDropRow - mTopRowIndex) - mRowHeight / 2;
    2880               0 :     nsRect feedbackRect(mInnerBox.x, yPos, mInnerBox.width, mRowHeight);
    2881               0 :     if (mSlots->mDropOrient == nsITreeView::DROP_AFTER)
    2882               0 :       feedbackRect.y += mRowHeight;
    2883                 : 
    2884               0 :     nsRect dirtyRect;
    2885               0 :     feedbackRect += aPt;
    2886               0 :     if (dirtyRect.IntersectRect(aDirtyRect, feedbackRect)) {
    2887               0 :       PaintDropFeedback(feedbackRect, PresContext(), aRenderingContext, aDirtyRect, aPt);
    2888                 :     }
    2889                 :   }
    2890               0 :   aRenderingContext.PopState();
    2891               0 : }
    2892                 : 
    2893                 : 
    2894                 : 
    2895                 : void
    2896               0 : nsTreeBodyFrame::PaintColumn(nsTreeColumn*        aColumn,
    2897                 :                              const nsRect&        aColumnRect,
    2898                 :                              nsPresContext*      aPresContext,
    2899                 :                              nsRenderingContext& aRenderingContext,
    2900                 :                              const nsRect&        aDirtyRect)
    2901                 : {
    2902               0 :   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
    2903                 : 
    2904                 :   // Now obtain the properties for our cell.
    2905               0 :   PrefillPropertyArray(-1, aColumn);
    2906               0 :   mView->GetColumnProperties(aColumn, mScratchArray);
    2907                 : 
    2908                 :   // Resolve style for the column.  It contains all the info we need to lay ourselves
    2909                 :   // out and to paint.
    2910               0 :   nsStyleContext* colContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecolumn);
    2911                 : 
    2912                 :   // Obtain the margins for the cell and then deflate our rect by that 
    2913                 :   // amount.  The cell is assumed to be contained within the deflated rect.
    2914               0 :   nsRect colRect(aColumnRect);
    2915               0 :   nsMargin colMargin;
    2916               0 :   colContext->GetStyleMargin()->GetMargin(colMargin);
    2917               0 :   colRect.Deflate(colMargin);
    2918                 : 
    2919               0 :   PaintBackgroundLayer(colContext, aPresContext, aRenderingContext, colRect, aDirtyRect);
    2920               0 : }
    2921                 : 
    2922                 : void
    2923               0 : nsTreeBodyFrame::PaintRow(PRInt32              aRowIndex,
    2924                 :                           const nsRect&        aRowRect,
    2925                 :                           nsPresContext*       aPresContext,
    2926                 :                           nsRenderingContext& aRenderingContext,
    2927                 :                           const nsRect&        aDirtyRect,
    2928                 :                           nsPoint              aPt)
    2929                 : {
    2930                 :   // We have been given a rect for our row.  We treat this row like a full-blown
    2931                 :   // frame, meaning that it can have borders, margins, padding, and a background.
    2932                 :   
    2933                 :   // Without a view, we have no data. Check for this up front.
    2934               0 :   if (!mView)
    2935               0 :     return;
    2936                 : 
    2937                 :   nsresult rv;
    2938                 : 
    2939                 :   // Now obtain the properties for our row.
    2940                 :   // XXX Automatically fill in the following props: open, closed, container, leaf, selected, focused
    2941               0 :   PrefillPropertyArray(aRowIndex, nsnull);
    2942               0 :   mView->GetRowProperties(aRowIndex, mScratchArray);
    2943                 : 
    2944                 :   // Resolve style for the row.  It contains all the info we need to lay ourselves
    2945                 :   // out and to paint.
    2946               0 :   nsStyleContext* rowContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreerow);
    2947                 : 
    2948                 :   // Obtain the margins for the row and then deflate our rect by that 
    2949                 :   // amount.  The row is assumed to be contained within the deflated rect.
    2950               0 :   nsRect rowRect(aRowRect);
    2951               0 :   nsMargin rowMargin;
    2952               0 :   rowContext->GetStyleMargin()->GetMargin(rowMargin);
    2953               0 :   rowRect.Deflate(rowMargin);
    2954                 : 
    2955                 :   // Paint our borders and background for our row rect.
    2956                 :   // If a -moz-appearance is provided, use theme drawing only if the current row
    2957                 :   // is not selected (since we draw the selection as part of drawing the background).
    2958               0 :   bool useTheme = false;
    2959               0 :   nsITheme *theme = nsnull;
    2960               0 :   const nsStyleDisplay* displayData = rowContext->GetStyleDisplay();
    2961               0 :   if (displayData->mAppearance) {
    2962               0 :     theme = aPresContext->GetTheme();
    2963               0 :     if (theme && theme->ThemeSupportsWidget(aPresContext, nsnull, displayData->mAppearance))
    2964               0 :       useTheme = true;
    2965                 :   }
    2966               0 :   bool isSelected = false;
    2967               0 :   nsCOMPtr<nsITreeSelection> selection;
    2968               0 :   mView->GetSelection(getter_AddRefs(selection));
    2969               0 :   if (selection) 
    2970               0 :     selection->IsSelected(aRowIndex, &isSelected);
    2971               0 :   if (useTheme && !isSelected) {
    2972               0 :     nsRect dirty;
    2973               0 :     dirty.IntersectRect(rowRect, aDirtyRect);
    2974                 :     theme->DrawWidgetBackground(&aRenderingContext, this, 
    2975               0 :                                 displayData->mAppearance, rowRect, dirty);
    2976                 :   } else {
    2977               0 :     PaintBackgroundLayer(rowContext, aPresContext, aRenderingContext, rowRect, aDirtyRect);
    2978                 :   }
    2979                 :   
    2980                 :   // Adjust the rect for its border and padding.
    2981               0 :   nsRect originalRowRect = rowRect;
    2982               0 :   AdjustForBorderPadding(rowContext, rowRect);
    2983                 : 
    2984               0 :   bool isSeparator = false;
    2985               0 :   mView->IsSeparator(aRowIndex, &isSeparator);
    2986               0 :   if (isSeparator) {
    2987                 :     // The row is a separator.
    2988                 : 
    2989               0 :     nscoord primaryX = rowRect.x;
    2990               0 :     nsTreeColumn* primaryCol = mColumns->GetPrimaryColumn();
    2991               0 :     if (primaryCol) {
    2992                 :       // Paint the primary cell.
    2993               0 :       nsRect cellRect;
    2994               0 :       rv = primaryCol->GetRect(this, rowRect.y, rowRect.height, &cellRect);
    2995               0 :       if (NS_FAILED(rv)) {
    2996               0 :         NS_NOTREACHED("primary column is invalid");
    2997                 :         return;
    2998                 :       }
    2999                 : 
    3000               0 :       if (OffsetForHorzScroll(cellRect, false)) {
    3001               0 :         cellRect.x += aPt.x;
    3002               0 :         nsRect dirtyRect;
    3003                 :         nsRect checkRect(cellRect.x, originalRowRect.y,
    3004               0 :                          cellRect.width, originalRowRect.height);
    3005               0 :         if (dirtyRect.IntersectRect(aDirtyRect, checkRect))
    3006                 :           PaintCell(aRowIndex, primaryCol, cellRect, aPresContext,
    3007               0 :                     aRenderingContext, aDirtyRect, primaryX, aPt);
    3008                 :       }
    3009                 : 
    3010                 :       // Paint the left side of the separator.
    3011                 :       nscoord currX;
    3012               0 :       nsTreeColumn* previousCol = primaryCol->GetPrevious();
    3013               0 :       if (previousCol) {
    3014               0 :         nsRect prevColRect;
    3015               0 :         rv = previousCol->GetRect(this, 0, 0, &prevColRect);
    3016               0 :         if (NS_SUCCEEDED(rv)) {
    3017               0 :           currX = (prevColRect.x - mHorzPosition) + prevColRect.width + aPt.x;
    3018                 :         } else {
    3019               0 :           NS_NOTREACHED("The column before the primary column is invalid");
    3020               0 :           currX = rowRect.x;
    3021                 :         }
    3022                 :       } else {
    3023               0 :         currX = rowRect.x;
    3024                 :       }
    3025                 : 
    3026                 :       PRInt32 level;
    3027               0 :       mView->GetLevel(aRowIndex, &level);
    3028               0 :       if (level == 0)
    3029               0 :         currX += mIndentation;
    3030                 : 
    3031               0 :       if (currX > rowRect.x) {
    3032               0 :         nsRect separatorRect(rowRect);
    3033               0 :         separatorRect.width -= rowRect.x + rowRect.width - currX;
    3034               0 :         PaintSeparator(aRowIndex, separatorRect, aPresContext, aRenderingContext, aDirtyRect);
    3035                 :       }
    3036                 :     }
    3037                 : 
    3038                 :     // Paint the right side (whole) separator.
    3039               0 :     nsRect separatorRect(rowRect);
    3040               0 :     if (primaryX > rowRect.x) {
    3041               0 :       separatorRect.width -= primaryX - rowRect.x;
    3042               0 :       separatorRect.x += primaryX - rowRect.x;
    3043                 :     }
    3044               0 :     PaintSeparator(aRowIndex, separatorRect, aPresContext, aRenderingContext, aDirtyRect);
    3045                 :   }
    3046                 :   else {
    3047                 :     // Now loop over our cells. Only paint a cell if it intersects with our dirty rect.
    3048               0 :     for (nsTreeColumn* currCol = mColumns->GetFirstColumn(); currCol;
    3049                 :          currCol = currCol->GetNext()) {
    3050               0 :       nsRect cellRect;
    3051               0 :       rv = currCol->GetRect(this, rowRect.y, rowRect.height, &cellRect);
    3052                 :       // Don't paint cells in hidden columns.
    3053               0 :       if (NS_FAILED(rv) || cellRect.width == 0)
    3054               0 :         continue;
    3055                 : 
    3056               0 :       if (OffsetForHorzScroll(cellRect, false)) {
    3057               0 :         cellRect.x += aPt.x;
    3058                 : 
    3059                 :         // for primary columns, use the row's vertical size so that the
    3060                 :         // lines get drawn properly
    3061               0 :         nsRect checkRect = cellRect;
    3062               0 :         if (currCol->IsPrimary())
    3063                 :           checkRect = nsRect(cellRect.x, originalRowRect.y,
    3064               0 :                              cellRect.width, originalRowRect.height);
    3065                 : 
    3066               0 :         nsRect dirtyRect;
    3067                 :         nscoord dummy;
    3068               0 :         if (dirtyRect.IntersectRect(aDirtyRect, checkRect))
    3069                 :           PaintCell(aRowIndex, currCol, cellRect, aPresContext,
    3070               0 :                     aRenderingContext, aDirtyRect, dummy, aPt);
    3071                 :       }
    3072                 :     }
    3073                 :   }
    3074                 : }
    3075                 : 
    3076                 : void
    3077               0 : nsTreeBodyFrame::PaintSeparator(PRInt32              aRowIndex,
    3078                 :                                 const nsRect&        aSeparatorRect,
    3079                 :                                 nsPresContext*      aPresContext,
    3080                 :                                 nsRenderingContext& aRenderingContext,
    3081                 :                                 const nsRect&        aDirtyRect)
    3082                 : {
    3083                 :   // Resolve style for the separator.
    3084               0 :   nsStyleContext* separatorContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeseparator);
    3085               0 :   bool useTheme = false;
    3086               0 :   nsITheme *theme = nsnull;
    3087               0 :   const nsStyleDisplay* displayData = separatorContext->GetStyleDisplay();
    3088               0 :   if ( displayData->mAppearance ) {
    3089               0 :     theme = aPresContext->GetTheme();
    3090               0 :     if (theme && theme->ThemeSupportsWidget(aPresContext, nsnull, displayData->mAppearance))
    3091               0 :       useTheme = true;
    3092                 :   }
    3093                 : 
    3094                 :   // use -moz-appearance if provided.
    3095               0 :   if (useTheme) {
    3096               0 :     nsRect dirty;
    3097               0 :     dirty.IntersectRect(aSeparatorRect, aDirtyRect);
    3098                 :     theme->DrawWidgetBackground(&aRenderingContext, this,
    3099               0 :                                 displayData->mAppearance, aSeparatorRect, dirty); 
    3100                 :   }
    3101                 :   else {
    3102               0 :     const nsStylePosition* stylePosition = separatorContext->GetStylePosition();
    3103                 : 
    3104                 :     // Obtain the height for the separator or use the default value.
    3105                 :     nscoord height;
    3106               0 :     if (stylePosition->mHeight.GetUnit() == eStyleUnit_Coord)
    3107               0 :       height = stylePosition->mHeight.GetCoordValue();
    3108                 :     else {
    3109                 :       // Use default height 2px.
    3110               0 :       height = nsPresContext::CSSPixelsToAppUnits(2);
    3111                 :     }
    3112                 : 
    3113                 :     // Obtain the margins for the separator and then deflate our rect by that 
    3114                 :     // amount. The separator is assumed to be contained within the deflated rect.
    3115               0 :     nsRect separatorRect(aSeparatorRect.x, aSeparatorRect.y, aSeparatorRect.width, height);
    3116               0 :     nsMargin separatorMargin;
    3117               0 :     separatorContext->GetStyleMargin()->GetMargin(separatorMargin);
    3118               0 :     separatorRect.Deflate(separatorMargin);
    3119                 : 
    3120                 :     // Center the separator.
    3121               0 :     separatorRect.y += (aSeparatorRect.height - height) / 2;
    3122                 : 
    3123               0 :     PaintBackgroundLayer(separatorContext, aPresContext, aRenderingContext, separatorRect, aDirtyRect);
    3124                 :   }
    3125               0 : }
    3126                 : 
    3127                 : void
    3128               0 : nsTreeBodyFrame::PaintCell(PRInt32              aRowIndex,
    3129                 :                            nsTreeColumn*        aColumn,
    3130                 :                            const nsRect&        aCellRect,
    3131                 :                            nsPresContext*       aPresContext,
    3132                 :                            nsRenderingContext& aRenderingContext,
    3133                 :                            const nsRect&        aDirtyRect,
    3134                 :                            nscoord&             aCurrX,
    3135                 :                            nsPoint              aPt)
    3136                 : {
    3137               0 :   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
    3138                 : 
    3139                 :   // Now obtain the properties for our cell.
    3140                 :   // XXX Automatically fill in the following props: open, closed, container, leaf, selected, focused, and the col ID.
    3141               0 :   PrefillPropertyArray(aRowIndex, aColumn);
    3142               0 :   mView->GetCellProperties(aRowIndex, aColumn, mScratchArray);
    3143                 : 
    3144                 :   // Resolve style for the cell.  It contains all the info we need to lay ourselves
    3145                 :   // out and to paint.
    3146               0 :   nsStyleContext* cellContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecell);
    3147                 : 
    3148               0 :   bool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
    3149                 : 
    3150                 :   // Obtain the margins for the cell and then deflate our rect by that 
    3151                 :   // amount.  The cell is assumed to be contained within the deflated rect.
    3152               0 :   nsRect cellRect(aCellRect);
    3153               0 :   nsMargin cellMargin;
    3154               0 :   cellContext->GetStyleMargin()->GetMargin(cellMargin);
    3155               0 :   cellRect.Deflate(cellMargin);
    3156                 : 
    3157                 :   // Paint our borders and background for our row rect.
    3158               0 :   PaintBackgroundLayer(cellContext, aPresContext, aRenderingContext, cellRect, aDirtyRect);
    3159                 : 
    3160                 :   // Adjust the rect for its border and padding.
    3161               0 :   AdjustForBorderPadding(cellContext, cellRect);
    3162                 : 
    3163               0 :   nscoord currX = cellRect.x;
    3164               0 :   nscoord remainingWidth = cellRect.width;
    3165                 : 
    3166                 :   // Now we paint the contents of the cells.
    3167                 :   // Directionality of the tree determines the order in which we paint.  
    3168                 :   // NS_STYLE_DIRECTION_LTR means paint from left to right.
    3169                 :   // NS_STYLE_DIRECTION_RTL means paint from right to left.
    3170                 : 
    3171               0 :   if (aColumn->IsPrimary()) {
    3172                 :     // If we're the primary column, we need to indent and paint the twisty and any connecting lines
    3173                 :     // between siblings.
    3174                 : 
    3175                 :     PRInt32 level;
    3176               0 :     mView->GetLevel(aRowIndex, &level);
    3177                 : 
    3178               0 :     if (!isRTL)
    3179               0 :       currX += mIndentation * level;
    3180               0 :     remainingWidth -= mIndentation * level;
    3181                 : 
    3182                 :     // Resolve the style to use for the connecting lines.
    3183               0 :     nsStyleContext* lineContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeline);
    3184                 :     
    3185               0 :     if (mIndentation && level &&
    3186               0 :         lineContext->GetStyleVisibility()->IsVisibleOrCollapsed()) {
    3187                 :       // Paint the thread lines.
    3188                 : 
    3189                 :       // Get the size of the twisty. We don't want to paint the twisty
    3190                 :       // before painting of connecting lines since it would paint lines over
    3191                 :       // the twisty. But we need to leave a place for it.
    3192               0 :       nsStyleContext* twistyContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreetwisty);
    3193                 : 
    3194               0 :       nsRect imageSize;
    3195               0 :       nsRect twistyRect(aCellRect);
    3196                 :       GetTwistyRect(aRowIndex, aColumn, imageSize, twistyRect, aPresContext,
    3197               0 :                     aRenderingContext, twistyContext);
    3198                 : 
    3199               0 :       nsMargin twistyMargin;
    3200               0 :       twistyContext->GetStyleMargin()->GetMargin(twistyMargin);
    3201               0 :       twistyRect.Inflate(twistyMargin);
    3202                 : 
    3203               0 :       aRenderingContext.PushState();
    3204                 : 
    3205               0 :       const nsStyleBorder* borderStyle = lineContext->GetStyleBorder();
    3206                 :       nscolor color;
    3207                 :       bool foreground;
    3208               0 :       borderStyle->GetBorderColor(NS_SIDE_LEFT, color, foreground);
    3209               0 :       if (foreground) {
    3210                 :         // GetBorderColor didn't touch color, thus grab it from the treeline context
    3211               0 :         color = lineContext->GetStyleColor()->mColor;
    3212                 :       }
    3213               0 :       aRenderingContext.SetColor(color);
    3214                 :       PRUint8 style;
    3215               0 :       style = borderStyle->GetBorderStyle(NS_SIDE_LEFT);
    3216               0 :       aRenderingContext.SetLineStyle(ConvertBorderStyleToLineStyle(style));
    3217                 : 
    3218               0 :       nscoord srcX = currX + twistyRect.width - mIndentation / 2;
    3219               0 :       nscoord lineY = (aRowIndex - mTopRowIndex) * mRowHeight + aPt.y;
    3220                 : 
    3221                 :       // Don't paint off our cell.
    3222               0 :       if (srcX <= cellRect.x + cellRect.width) {
    3223               0 :         nscoord destX = currX + twistyRect.width;
    3224               0 :         if (destX > cellRect.x + cellRect.width)
    3225               0 :           destX = cellRect.x + cellRect.width;
    3226               0 :         if (isRTL) {
    3227               0 :           srcX = currX + remainingWidth - (srcX - cellRect.x);
    3228               0 :           destX = currX + remainingWidth - (destX - cellRect.x);
    3229                 :         }
    3230               0 :         aRenderingContext.DrawLine(srcX, lineY + mRowHeight / 2, destX, lineY + mRowHeight / 2);
    3231                 :       }
    3232                 : 
    3233               0 :       PRInt32 currentParent = aRowIndex;
    3234               0 :       for (PRInt32 i = level; i > 0; i--) {
    3235               0 :         if (srcX <= cellRect.x + cellRect.width) {
    3236                 :           // Paint full vertical line only if we have next sibling.
    3237                 :           bool hasNextSibling;
    3238               0 :           mView->HasNextSibling(currentParent, aRowIndex, &hasNextSibling);
    3239               0 :           if (hasNextSibling)
    3240               0 :             aRenderingContext.DrawLine(srcX, lineY, srcX, lineY + mRowHeight);
    3241               0 :           else if (i == level)
    3242               0 :             aRenderingContext.DrawLine(srcX, lineY, srcX, lineY + mRowHeight / 2);
    3243                 :         }
    3244                 : 
    3245                 :         PRInt32 parent;
    3246               0 :         if (NS_FAILED(mView->GetParentIndex(currentParent, &parent)) || parent < 0)
    3247               0 :           break;
    3248               0 :         currentParent = parent;
    3249               0 :         srcX -= mIndentation;
    3250                 :       }
    3251                 : 
    3252               0 :       aRenderingContext.PopState();
    3253                 :     }
    3254                 : 
    3255                 :     // Always leave space for the twisty.
    3256               0 :     nsRect twistyRect(currX, cellRect.y, remainingWidth, cellRect.height);
    3257                 :     PaintTwisty(aRowIndex, aColumn, twistyRect, aPresContext, aRenderingContext, aDirtyRect,
    3258               0 :                 remainingWidth, currX);
    3259                 :   }
    3260                 :   
    3261                 :   // Now paint the icon for our cell.
    3262               0 :   nsRect iconRect(currX, cellRect.y, remainingWidth, cellRect.height);
    3263               0 :   nsRect dirtyRect;
    3264               0 :   if (dirtyRect.IntersectRect(aDirtyRect, iconRect))
    3265                 :     PaintImage(aRowIndex, aColumn, iconRect, aPresContext, aRenderingContext, aDirtyRect,
    3266               0 :                remainingWidth, currX);
    3267                 : 
    3268                 :   // Now paint our element, but only if we aren't a cycler column.
    3269                 :   // XXX until we have the ability to load images, allow the view to 
    3270                 :   // insert text into cycler columns...
    3271               0 :   if (!aColumn->IsCycler()) {
    3272               0 :     nsRect elementRect(currX, cellRect.y, remainingWidth, cellRect.height);
    3273               0 :     nsRect dirtyRect;
    3274               0 :     if (dirtyRect.IntersectRect(aDirtyRect, elementRect)) {
    3275               0 :       bool textRTL = cellContext->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
    3276               0 :       switch (aColumn->GetType()) {
    3277                 :         case nsITreeColumn::TYPE_TEXT:
    3278                 :           PaintText(aRowIndex, aColumn, elementRect, aPresContext, aRenderingContext, aDirtyRect, currX,
    3279               0 :                     textRTL);
    3280               0 :           break;
    3281                 :         case nsITreeColumn::TYPE_CHECKBOX:
    3282               0 :           PaintCheckbox(aRowIndex, aColumn, elementRect, aPresContext, aRenderingContext, aDirtyRect);
    3283               0 :           break;
    3284                 :         case nsITreeColumn::TYPE_PROGRESSMETER:
    3285                 :           PRInt32 state;
    3286               0 :           mView->GetProgressMode(aRowIndex, aColumn, &state);
    3287               0 :           switch (state) {
    3288                 :             case nsITreeView::PROGRESS_NORMAL:
    3289                 :             case nsITreeView::PROGRESS_UNDETERMINED:
    3290               0 :               PaintProgressMeter(aRowIndex, aColumn, elementRect, aPresContext, aRenderingContext, aDirtyRect);
    3291               0 :               break;
    3292                 :             case nsITreeView::PROGRESS_NONE:
    3293                 :             default:
    3294                 :               PaintText(aRowIndex, aColumn, elementRect, aPresContext, aRenderingContext, aDirtyRect, currX,
    3295               0 :                         textRTL);
    3296               0 :               break;
    3297                 :           }
    3298               0 :           break;
    3299                 :       }
    3300                 :     }
    3301                 :   }
    3302                 : 
    3303               0 :   aCurrX = currX;
    3304               0 : }
    3305                 : 
    3306                 : void
    3307               0 : nsTreeBodyFrame::PaintTwisty(PRInt32              aRowIndex,
    3308                 :                              nsTreeColumn*        aColumn,
    3309                 :                              const nsRect&        aTwistyRect,
    3310                 :                              nsPresContext*      aPresContext,
    3311                 :                              nsRenderingContext& aRenderingContext,
    3312                 :                              const nsRect&        aDirtyRect,
    3313                 :                              nscoord&             aRemainingWidth,
    3314                 :                              nscoord&             aCurrX)
    3315                 : {
    3316               0 :   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
    3317                 : 
    3318               0 :   bool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
    3319               0 :   nscoord rightEdge = aCurrX + aRemainingWidth;
    3320                 :   // Paint the twisty, but only if we are a non-empty container.
    3321               0 :   bool shouldPaint = false;
    3322               0 :   bool isContainer = false;
    3323               0 :   mView->IsContainer(aRowIndex, &isContainer);
    3324               0 :   if (isContainer) {
    3325               0 :     bool isContainerEmpty = false;
    3326               0 :     mView->IsContainerEmpty(aRowIndex, &isContainerEmpty);
    3327               0 :     if (!isContainerEmpty)
    3328               0 :       shouldPaint = true;
    3329                 :   }
    3330                 : 
    3331                 :   // Resolve style for the twisty.
    3332               0 :   nsStyleContext* twistyContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreetwisty);
    3333                 : 
    3334                 :   // Obtain the margins for the twisty and then deflate our rect by that 
    3335                 :   // amount.  The twisty is assumed to be contained within the deflated rect.
    3336               0 :   nsRect twistyRect(aTwistyRect);
    3337               0 :   nsMargin twistyMargin;
    3338               0 :   twistyContext->GetStyleMargin()->GetMargin(twistyMargin);
    3339               0 :   twistyRect.Deflate(twistyMargin);
    3340                 : 
    3341               0 :   nsRect imageSize;
    3342                 :   nsITheme* theme = GetTwistyRect(aRowIndex, aColumn, imageSize, twistyRect,
    3343               0 :                                   aPresContext, aRenderingContext, twistyContext);
    3344                 : 
    3345                 :   // Subtract out the remaining width.  This is done even when we don't actually paint a twisty in 
    3346                 :   // this cell, so that cells in different rows still line up.
    3347               0 :   nsRect copyRect(twistyRect);
    3348               0 :   copyRect.Inflate(twistyMargin);
    3349               0 :   aRemainingWidth -= copyRect.width;
    3350               0 :   if (!isRTL)
    3351               0 :     aCurrX += copyRect.width;
    3352                 : 
    3353               0 :   if (shouldPaint) {
    3354                 :     // Paint our borders and background for our image rect.
    3355               0 :     PaintBackgroundLayer(twistyContext, aPresContext, aRenderingContext, twistyRect, aDirtyRect);
    3356                 : 
    3357               0 :     if (theme) {
    3358               0 :       if (isRTL)
    3359               0 :         twistyRect.x = rightEdge - twistyRect.width;
    3360                 :       // yeah, I know it says we're drawing a background, but a twisty is really a fg
    3361                 :       // object since it doesn't have anything that gecko would want to draw over it. Besides,
    3362                 :       // we have to prevent imagelib from drawing it.
    3363               0 :       nsRect dirty;
    3364               0 :       dirty.IntersectRect(twistyRect, aDirtyRect);
    3365                 :       theme->DrawWidgetBackground(&aRenderingContext, this, 
    3366               0 :                                   twistyContext->GetStyleDisplay()->mAppearance, twistyRect, dirty);
    3367                 :     }
    3368                 :     else {
    3369                 :       // Time to paint the twisty.
    3370                 :       // Adjust the rect for its border and padding.
    3371               0 :       nsMargin bp(0,0,0,0);
    3372               0 :       GetBorderPadding(twistyContext, bp);
    3373               0 :       twistyRect.Deflate(bp);
    3374               0 :       if (isRTL)
    3375               0 :         twistyRect.x = rightEdge - twistyRect.width;
    3376               0 :       imageSize.Deflate(bp);
    3377                 : 
    3378                 :       // Get the image for drawing.
    3379               0 :       nsCOMPtr<imgIContainer> image;
    3380               0 :       bool useImageRegion = true;
    3381               0 :       GetImage(aRowIndex, aColumn, true, twistyContext, useImageRegion, getter_AddRefs(image));
    3382               0 :       if (image) {
    3383               0 :         nsPoint pt = twistyRect.TopLeft();
    3384                 : 
    3385                 :         // Center the image. XXX Obey vertical-align style prop?
    3386               0 :         if (imageSize.height < twistyRect.height) {
    3387               0 :           pt.y += (twistyRect.height - imageSize.height)/2;
    3388                 :         }
    3389                 :           
    3390                 :         // Paint the image.
    3391                 :         nsLayoutUtils::DrawSingleUnscaledImage(&aRenderingContext, image,
    3392                 :             gfxPattern::FILTER_NEAREST, pt, &aDirtyRect,
    3393               0 :             imgIContainer::FLAG_NONE, &imageSize);
    3394                 :       }
    3395                 :     }
    3396                 :   }
    3397               0 : }
    3398                 : 
    3399                 : void
    3400               0 : nsTreeBodyFrame::PaintImage(PRInt32              aRowIndex,
    3401                 :                             nsTreeColumn*        aColumn,
    3402                 :                             const nsRect&        aImageRect,
    3403                 :                             nsPresContext*       aPresContext,
    3404                 :                             nsRenderingContext& aRenderingContext,
    3405                 :                             const nsRect&        aDirtyRect,
    3406                 :                             nscoord&             aRemainingWidth,
    3407                 :                             nscoord&             aCurrX)
    3408                 : {
    3409               0 :   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
    3410                 : 
    3411               0 :   bool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
    3412               0 :   nscoord rightEdge = aCurrX + aRemainingWidth;
    3413                 :   // Resolve style for the image.
    3414               0 :   nsStyleContext* imageContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeimage);
    3415                 : 
    3416                 :   // Obtain opacity value for the image.
    3417               0 :   float opacity = imageContext->GetStyleDisplay()->mOpacity;
    3418                 : 
    3419                 :   // Obtain the margins for the image and then deflate our rect by that
    3420                 :   // amount.  The image is assumed to be contained within the deflated rect.
    3421               0 :   nsRect imageRect(aImageRect);
    3422               0 :   nsMargin imageMargin;
    3423               0 :   imageContext->GetStyleMargin()->GetMargin(imageMargin);
    3424               0 :   imageRect.Deflate(imageMargin);
    3425                 : 
    3426                 :   // Get the image.
    3427               0 :   bool useImageRegion = true;
    3428               0 :   nsCOMPtr<imgIContainer> image;
    3429               0 :   GetImage(aRowIndex, aColumn, false, imageContext, useImageRegion, getter_AddRefs(image));
    3430                 : 
    3431                 :   // Get the image destination size.
    3432               0 :   nsSize imageDestSize = GetImageDestSize(imageContext, useImageRegion, image);
    3433               0 :   if (!imageDestSize.width || !imageDestSize.height)
    3434                 :     return;
    3435                 : 
    3436                 :   // Get the borders and padding.
    3437               0 :   nsMargin bp(0,0,0,0);
    3438               0 :   GetBorderPadding(imageContext, bp);
    3439                 : 
    3440                 :   // destRect will be passed as the aDestRect argument in the DrawImage method.
    3441                 :   // Start with the imageDestSize width and height.
    3442               0 :   nsRect destRect(0, 0, imageDestSize.width, imageDestSize.height);
    3443                 :   // Inflate destRect for borders and padding so that we can compare/adjust
    3444                 :   // with respect to imageRect.
    3445               0 :   destRect.Inflate(bp);
    3446                 : 
    3447                 :   // The destRect width and height have not been adjusted to fit within the
    3448                 :   // cell width and height.
    3449                 :   // We must adjust the width even if image is null, because the width is used
    3450                 :   // to update the aRemainingWidth and aCurrX values.
    3451                 :   // Since the height isn't used unless the image is not null, we will adjust
    3452                 :   // the height inside the if (image) block below.
    3453                 : 
    3454               0 :   if (destRect.width > imageRect.width) {
    3455                 :     // The destRect is too wide to fit within the cell width.
    3456                 :     // Adjust destRect width to fit within the cell width.
    3457               0 :     destRect.width = imageRect.width;
    3458                 :   }
    3459                 :   else {
    3460                 :     // The cell is wider than the destRect.
    3461                 :     // In a cycler column, the image is centered horizontally.
    3462               0 :     if (!aColumn->IsCycler()) {
    3463                 :       // If this column is not a cycler, we won't center the image horizontally.
    3464                 :       // We adjust the imageRect width so that the image is placed at the start
    3465                 :       // of the cell.
    3466               0 :       imageRect.width = destRect.width;
    3467                 :     }
    3468                 :   }
    3469                 : 
    3470               0 :   if (image) {
    3471               0 :     if (isRTL)
    3472               0 :       imageRect.x = rightEdge - imageRect.width;
    3473                 :     // Paint our borders and background for our image rect
    3474               0 :     PaintBackgroundLayer(imageContext, aPresContext, aRenderingContext, imageRect, aDirtyRect);
    3475                 : 
    3476                 :     // The destRect x and y have not been set yet. Let's do that now.
    3477                 :     // Initially, we use the imageRect x and y.
    3478               0 :     destRect.x = imageRect.x;
    3479               0 :     destRect.y = imageRect.y;
    3480                 : 
    3481               0 :     if (destRect.width < imageRect.width) {
    3482                 :       // The destRect width is smaller than the cell width.
    3483                 :       // Center the image horizontally in the cell.
    3484                 :       // Adjust the destRect x accordingly.
    3485               0 :       destRect.x += (imageRect.width - destRect.width)/2;
    3486                 :     }
    3487                 : 
    3488                 :     // Now it's time to adjust the destRect height to fit within the cell height.
    3489               0 :     if (destRect.height > imageRect.height) {
    3490                 :       // The destRect height is larger than the cell height.
    3491                 :       // Adjust destRect height to fit within the cell height.
    3492               0 :       destRect.height = imageRect.height;
    3493                 :     }
    3494               0 :     else if (destRect.height < imageRect.height) {
    3495                 :       // The destRect height is smaller than the cell height.
    3496                 :       // Center the image vertically in the cell.
    3497                 :       // Adjust the destRect y accordingly.
    3498               0 :       destRect.y += (imageRect.height - destRect.height)/2;
    3499                 :     }
    3500                 : 
    3501                 :     // It's almost time to paint the image.
    3502                 :     // Deflate destRect for the border and padding.
    3503               0 :     destRect.Deflate(bp);
    3504                 : 
    3505                 :     // Get the image source rectangle - the rectangle containing the part of
    3506                 :     // the image that we are going to display.
    3507                 :     // sourceRect will be passed as the aSrcRect argument in the DrawImage method.
    3508               0 :     nsRect sourceRect = GetImageSourceRect(imageContext, useImageRegion, image);
    3509                 : 
    3510                 :     // Let's say that the image is 100 pixels tall and
    3511                 :     // that the CSS has specified that the destination height should be 50
    3512                 :     // pixels tall. Let's say that the cell height is only 20 pixels. So, in
    3513                 :     // those 20 visible pixels, we want to see the top 20/50ths of the image.
    3514                 :     // So, the sourceRect.height should be 100 * 20 / 50, which is 40 pixels.
    3515                 :     // Essentially, we are scaling the image as dictated by the CSS destination
    3516                 :     // height and width, and we are then clipping the scaled image by the cell
    3517                 :     // width and height.
    3518               0 :     nsIntSize rawImageSize;
    3519               0 :     image->GetWidth(&rawImageSize.width);
    3520               0 :     image->GetHeight(&rawImageSize.height);
    3521                 :     nsRect wholeImageDest =
    3522                 :       nsLayoutUtils::GetWholeImageDestination(rawImageSize, sourceRect,
    3523               0 :           nsRect(destRect.TopLeft(), imageDestSize));
    3524                 : 
    3525               0 :     gfxContext* ctx = aRenderingContext.ThebesContext();
    3526               0 :     if (opacity != 1.0f) {
    3527               0 :       ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
    3528                 :     }
    3529                 : 
    3530                 :     nsLayoutUtils::DrawImage(&aRenderingContext, image,
    3531                 :         nsLayoutUtils::GetGraphicsFilterForFrame(this),
    3532                 :         wholeImageDest, destRect, destRect.TopLeft(), aDirtyRect,
    3533               0 :         imgIContainer::FLAG_NONE);
    3534                 : 
    3535               0 :     if (opacity != 1.0f) {
    3536               0 :       ctx->PopGroupToSource();
    3537               0 :       ctx->Paint(opacity);
    3538                 :     }
    3539                 :   }
    3540                 : 
    3541                 :   // Update the aRemainingWidth and aCurrX values.
    3542               0 :   imageRect.Inflate(imageMargin);
    3543               0 :   aRemainingWidth -= imageRect.width;
    3544               0 :   if (!isRTL)
    3545               0 :     aCurrX += imageRect.width;
    3546                 : }
    3547                 : 
    3548                 : void
    3549               0 : nsTreeBodyFrame::PaintText(PRInt32              aRowIndex,
    3550                 :                            nsTreeColumn*        aColumn,
    3551                 :                            const nsRect&        aTextRect,
    3552                 :                            nsPresContext*      aPresContext,
    3553                 :                            nsRenderingContext& aRenderingContext,
    3554                 :                            const nsRect&        aDirtyRect,
    3555                 :                            nscoord&             aCurrX,
    3556                 :                            bool                 aTextRTL)
    3557                 : {
    3558               0 :   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
    3559                 : 
    3560               0 :   bool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
    3561                 : 
    3562                 :   // Now obtain the text for our cell.
    3563               0 :   nsAutoString text;
    3564               0 :   mView->GetCellText(aRowIndex, aColumn, text);
    3565                 :   // We're going to paint this text so we need to ensure bidi is enabled if
    3566                 :   // necessary
    3567               0 :   CheckTextForBidi(text);
    3568                 : 
    3569               0 :   if (text.Length() == 0)
    3570                 :     return; // Don't paint an empty string. XXX What about background/borders? Still paint?
    3571                 : 
    3572                 :   // Resolve style for the text.  It contains all the info we need to lay ourselves
    3573                 :   // out and to paint.
    3574               0 :   nsStyleContext* textContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecelltext);
    3575                 : 
    3576                 :   // Obtain opacity value for the image.
    3577               0 :   float opacity = textContext->GetStyleDisplay()->mOpacity;
    3578                 : 
    3579                 :   // Obtain the margins for the text and then deflate our rect by that 
    3580                 :   // amount.  The text is assumed to be contained within the deflated rect.
    3581               0 :   nsRect textRect(aTextRect);
    3582               0 :   nsMargin textMargin;
    3583               0 :   textContext->GetStyleMargin()->GetMargin(textMargin);
    3584               0 :   textRect.Deflate(textMargin);
    3585                 : 
    3586                 :   // Adjust the rect for its border and padding.
    3587               0 :   nsMargin bp(0,0,0,0);
    3588               0 :   GetBorderPadding(textContext, bp);
    3589               0 :   textRect.Deflate(bp);
    3590                 : 
    3591                 :   // Compute our text size.
    3592               0 :   nsRefPtr<nsFontMetrics> fontMet;
    3593                 :   nsLayoutUtils::GetFontMetricsForStyleContext(textContext,
    3594               0 :                                                getter_AddRefs(fontMet));
    3595                 : 
    3596               0 :   nscoord height = fontMet->MaxHeight();
    3597               0 :   nscoord baseline = fontMet->MaxAscent();
    3598                 : 
    3599                 :   // Center the text. XXX Obey vertical-align style prop?
    3600               0 :   if (height < textRect.height) {
    3601               0 :     textRect.y += (textRect.height - height)/2;
    3602               0 :     textRect.height = height;
    3603                 :   }
    3604                 : 
    3605                 :   // Set our font.
    3606               0 :   aRenderingContext.SetFont(fontMet);
    3607                 : 
    3608               0 :   AdjustForCellText(text, aRowIndex, aColumn, aRenderingContext, textRect);
    3609               0 :   textRect.Inflate(bp);
    3610                 : 
    3611                 :   // Subtract out the remaining width.
    3612               0 :   if (!isRTL)
    3613               0 :     aCurrX += textRect.width + textMargin.LeftRight();
    3614                 : 
    3615               0 :   PaintBackgroundLayer(textContext, aPresContext, aRenderingContext, textRect, aDirtyRect);
    3616                 : 
    3617                 :   // Time to paint our text.
    3618               0 :   textRect.Deflate(bp);
    3619                 : 
    3620                 :   // Set our color.
    3621               0 :   aRenderingContext.SetColor(textContext->GetStyleColor()->mColor);
    3622                 : 
    3623                 :   // Draw decorations.
    3624               0 :   PRUint8 decorations = textContext->GetStyleTextReset()->mTextDecorationLine;
    3625                 : 
    3626                 :   nscoord offset;
    3627                 :   nscoord size;
    3628               0 :   if (decorations & (NS_FONT_DECORATION_OVERLINE | NS_FONT_DECORATION_UNDERLINE)) {
    3629               0 :     fontMet->GetUnderline(offset, size);
    3630               0 :     if (decorations & NS_FONT_DECORATION_OVERLINE)
    3631               0 :       aRenderingContext.FillRect(textRect.x, textRect.y, textRect.width, size);
    3632               0 :     if (decorations & NS_FONT_DECORATION_UNDERLINE)
    3633               0 :       aRenderingContext.FillRect(textRect.x, textRect.y + baseline - offset, textRect.width, size);
    3634                 :   }
    3635               0 :   if (decorations & NS_FONT_DECORATION_LINE_THROUGH) {
    3636               0 :     fontMet->GetStrikeout(offset, size);
    3637               0 :     aRenderingContext.FillRect(textRect.x, textRect.y + baseline - offset, textRect.width, size);
    3638                 :   }
    3639                 :   PRUint8 direction = aTextRTL ? NS_STYLE_DIRECTION_RTL :
    3640               0 :                                  NS_STYLE_DIRECTION_LTR;
    3641                 : 
    3642               0 :   gfxContext* ctx = aRenderingContext.ThebesContext();
    3643               0 :   if (opacity != 1.0f) {
    3644               0 :     ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
    3645                 :   }
    3646                 : 
    3647               0 :   nsLayoutUtils::DrawString(this, &aRenderingContext, text.get(), text.Length(),
    3648               0 :                             textRect.TopLeft() + nsPoint(0, baseline), direction);
    3649                 : 
    3650               0 :   if (opacity != 1.0f) {
    3651               0 :     ctx->PopGroupToSource();
    3652               0 :     ctx->Paint(opacity);
    3653                 :   }
    3654                 : 
    3655                 : }
    3656                 : 
    3657                 : void
    3658               0 : nsTreeBodyFrame::PaintCheckbox(PRInt32              aRowIndex,
    3659                 :                                nsTreeColumn*        aColumn,
    3660                 :                                const nsRect&        aCheckboxRect,
    3661                 :                                nsPresContext*      aPresContext,
    3662                 :                                nsRenderingContext& aRenderingContext,
    3663                 :                                const nsRect&        aDirtyRect)
    3664                 : {
    3665               0 :   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
    3666                 : 
    3667                 :   // Resolve style for the checkbox.
    3668               0 :   nsStyleContext* checkboxContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecheckbox);
    3669                 : 
    3670               0 :   nscoord rightEdge = aCheckboxRect.XMost();
    3671                 : 
    3672                 :   // Obtain the margins for the checkbox and then deflate our rect by that 
    3673                 :   // amount.  The checkbox is assumed to be contained within the deflated rect.
    3674               0 :   nsRect checkboxRect(aCheckboxRect);
    3675               0 :   nsMargin checkboxMargin;
    3676               0 :   checkboxContext->GetStyleMargin()->GetMargin(checkboxMargin);
    3677               0 :   checkboxRect.Deflate(checkboxMargin);
    3678                 :   
    3679               0 :   nsRect imageSize = GetImageSize(aRowIndex, aColumn, true, checkboxContext);
    3680                 : 
    3681               0 :   if (imageSize.height > checkboxRect.height)
    3682               0 :     imageSize.height = checkboxRect.height;
    3683               0 :   if (imageSize.width > checkboxRect.width)
    3684               0 :     imageSize.width = checkboxRect.width;
    3685                 : 
    3686               0 :   if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL)
    3687               0 :     checkboxRect.x = rightEdge - checkboxRect.width;
    3688                 : 
    3689                 :   // Paint our borders and background for our image rect.
    3690               0 :   PaintBackgroundLayer(checkboxContext, aPresContext, aRenderingContext, checkboxRect, aDirtyRect);
    3691                 : 
    3692                 :   // Time to paint the checkbox.
    3693                 :   // Adjust the rect for its border and padding.
    3694               0 :   nsMargin bp(0,0,0,0);
    3695               0 :   GetBorderPadding(checkboxContext, bp);
    3696               0 :   checkboxRect.Deflate(bp);
    3697                 : 
    3698                 :   // Get the image for drawing.
    3699               0 :   nsCOMPtr<imgIContainer> image;
    3700               0 :   bool useImageRegion = true;
    3701               0 :   GetImage(aRowIndex, aColumn, true, checkboxContext, useImageRegion, getter_AddRefs(image));
    3702               0 :   if (image) {
    3703               0 :     nsPoint pt = checkboxRect.TopLeft();
    3704                 :           
    3705               0 :     if (imageSize.height < checkboxRect.height) {
    3706               0 :       pt.y += (checkboxRect.height - imageSize.height)/2;
    3707                 :     }
    3708                 : 
    3709               0 :     if (imageSize.width < checkboxRect.width) {
    3710               0 :       pt.x += (checkboxRect.width - imageSize.width)/2;
    3711                 :     }
    3712                 : 
    3713                 :     // Paint the image.
    3714                 :     nsLayoutUtils::DrawSingleUnscaledImage(&aRenderingContext, image,
    3715                 :         gfxPattern::FILTER_NEAREST, pt, &aDirtyRect,
    3716               0 :         imgIContainer::FLAG_NONE, &imageSize);
    3717                 :   }
    3718               0 : }
    3719                 : 
    3720                 : void
    3721               0 : nsTreeBodyFrame::PaintProgressMeter(PRInt32              aRowIndex,
    3722                 :                                     nsTreeColumn*        aColumn,
    3723                 :                                     const nsRect&        aProgressMeterRect,
    3724                 :                                     nsPresContext*      aPresContext,
    3725                 :                                     nsRenderingContext& aRenderingContext,
    3726                 :                                     const nsRect&        aDirtyRect)
    3727                 : {
    3728               0 :   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
    3729                 : 
    3730                 :   // Resolve style for the progress meter.  It contains all the info we need
    3731                 :   // to lay ourselves out and to paint.
    3732               0 :   nsStyleContext* meterContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeprogressmeter);
    3733                 : 
    3734                 :   // Obtain the margins for the progress meter and then deflate our rect by that 
    3735                 :   // amount. The progress meter is assumed to be contained within the deflated
    3736                 :   // rect.
    3737               0 :   nsRect meterRect(aProgressMeterRect);
    3738               0 :   nsMargin meterMargin;
    3739               0 :   meterContext->GetStyleMargin()->GetMargin(meterMargin);
    3740               0 :   meterRect.Deflate(meterMargin);
    3741                 : 
    3742                 :   // Paint our borders and background for our progress meter rect.
    3743               0 :   PaintBackgroundLayer(meterContext, aPresContext, aRenderingContext, meterRect, aDirtyRect);
    3744                 : 
    3745                 :   // Time to paint our progress. 
    3746                 :   PRInt32 state;
    3747               0 :   mView->GetProgressMode(aRowIndex, aColumn, &state);
    3748               0 :   if (state == nsITreeView::PROGRESS_NORMAL) {
    3749                 :     // Adjust the rect for its border and padding.
    3750               0 :     AdjustForBorderPadding(meterContext, meterRect);
    3751                 : 
    3752                 :     // Set our color.
    3753               0 :     aRenderingContext.SetColor(meterContext->GetStyleColor()->mColor);
    3754                 : 
    3755                 :     // Now obtain the value for our cell.
    3756               0 :     nsAutoString value;
    3757               0 :     mView->GetCellValue(aRowIndex, aColumn, value);
    3758                 : 
    3759                 :     PRInt32 rv;
    3760               0 :     PRInt32 intValue = value.ToInteger(&rv);
    3761               0 :     if (intValue < 0)
    3762               0 :       intValue = 0;
    3763               0 :     else if (intValue > 100)
    3764               0 :       intValue = 100;
    3765                 : 
    3766               0 :     nscoord meterWidth = NSToCoordRound((float)intValue / 100 * meterRect.width);
    3767               0 :     if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL)
    3768               0 :       meterRect.x += meterRect.width - meterWidth; // right align
    3769               0 :     meterRect.width = meterWidth;
    3770               0 :     bool useImageRegion = true;
    3771               0 :     nsCOMPtr<imgIContainer> image;
    3772               0 :     GetImage(aRowIndex, aColumn, true, meterContext, useImageRegion, getter_AddRefs(image));
    3773               0 :     if (image) {
    3774                 :       PRInt32 width, height;
    3775               0 :       image->GetWidth(&width);
    3776               0 :       image->GetHeight(&height);
    3777               0 :       nsSize size(width*nsDeviceContext::AppUnitsPerCSSPixel(),
    3778               0 :                   height*nsDeviceContext::AppUnitsPerCSSPixel());
    3779                 :       nsLayoutUtils::DrawImage(&aRenderingContext, image,
    3780                 :           nsLayoutUtils::GetGraphicsFilterForFrame(this),
    3781               0 :           nsRect(meterRect.TopLeft(), size), meterRect, meterRect.TopLeft(),
    3782               0 :           aDirtyRect, imgIContainer::FLAG_NONE);
    3783                 :     } else {
    3784               0 :       aRenderingContext.FillRect(meterRect);
    3785                 :     }
    3786                 :   }
    3787               0 :   else if (state == nsITreeView::PROGRESS_UNDETERMINED) {
    3788                 :     // Adjust the rect for its border and padding.
    3789               0 :     AdjustForBorderPadding(meterContext, meterRect);
    3790                 : 
    3791               0 :     bool useImageRegion = true;
    3792               0 :     nsCOMPtr<imgIContainer> image;
    3793               0 :     GetImage(aRowIndex, aColumn, true, meterContext, useImageRegion, getter_AddRefs(image));
    3794               0 :     if (image) {
    3795                 :       PRInt32 width, height;
    3796               0 :       image->GetWidth(&width);
    3797               0 :       image->GetHeight(&height);
    3798               0 :       nsSize size(width*nsDeviceContext::AppUnitsPerCSSPixel(),
    3799               0 :                   height*nsDeviceContext::AppUnitsPerCSSPixel());
    3800                 :       nsLayoutUtils::DrawImage(&aRenderingContext, image,
    3801                 :           nsLayoutUtils::GetGraphicsFilterForFrame(this),
    3802               0 :           nsRect(meterRect.TopLeft(), size), meterRect, meterRect.TopLeft(),
    3803               0 :           aDirtyRect, imgIContainer::FLAG_NONE);
    3804                 :     }
    3805                 :   }
    3806               0 : }
    3807                 : 
    3808                 : 
    3809                 : void
    3810               0 : nsTreeBodyFrame::PaintDropFeedback(const nsRect&        aDropFeedbackRect,
    3811                 :                                    nsPresContext*      aPresContext,
    3812                 :                                    nsRenderingContext& aRenderingContext,
    3813                 :                                    const nsRect&        aDirtyRect,
    3814                 :                                    nsPoint              aPt)
    3815                 : {
    3816                 :   // Paint the drop feedback in between rows.
    3817                 : 
    3818                 :   nscoord currX;
    3819                 : 
    3820                 :   // Adjust for the primary cell.
    3821               0 :   nsTreeColumn* primaryCol = mColumns->GetPrimaryColumn();
    3822                 : 
    3823               0 :   if (primaryCol) {
    3824                 : #ifdef DEBUG
    3825                 :     nsresult rv =
    3826                 : #endif
    3827               0 :       primaryCol->GetXInTwips(this, &currX);
    3828               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "primary column is invalid?");
    3829                 : 
    3830               0 :     currX += aPt.x - mHorzPosition;
    3831                 :   } else {
    3832               0 :     currX = aDropFeedbackRect.x;
    3833                 :   }
    3834                 : 
    3835               0 :   PrefillPropertyArray(mSlots->mDropRow, primaryCol);
    3836                 : 
    3837                 :   // Resolve the style to use for the drop feedback.
    3838               0 :   nsStyleContext* feedbackContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreedropfeedback);
    3839                 : 
    3840                 :   // Paint only if it is visible.
    3841               0 :   if (feedbackContext->GetStyleVisibility()->IsVisibleOrCollapsed()) {
    3842                 :     PRInt32 level;
    3843               0 :     mView->GetLevel(mSlots->mDropRow, &level);
    3844                 : 
    3845                 :     // If our previous or next row has greater level use that for 
    3846                 :     // correct visual indentation.
    3847               0 :     if (mSlots->mDropOrient == nsITreeView::DROP_BEFORE) {
    3848               0 :       if (mSlots->mDropRow > 0) {
    3849                 :         PRInt32 previousLevel;
    3850               0 :         mView->GetLevel(mSlots->mDropRow - 1, &previousLevel);
    3851               0 :         if (previousLevel > level)
    3852               0 :           level = previousLevel;
    3853                 :       }
    3854                 :     }
    3855                 :     else {
    3856               0 :       if (mSlots->mDropRow < mRowCount - 1) {
    3857                 :         PRInt32 nextLevel;
    3858               0 :         mView->GetLevel(mSlots->mDropRow + 1, &nextLevel);
    3859               0 :         if (nextLevel > level)
    3860               0 :           level = nextLevel;
    3861                 :       }
    3862                 :     }
    3863                 : 
    3864               0 :     currX += mIndentation * level;
    3865                 : 
    3866               0 :     if (primaryCol){
    3867               0 :       nsStyleContext* twistyContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreetwisty);
    3868               0 :       nsRect imageSize;
    3869               0 :       nsRect twistyRect;
    3870                 :       GetTwistyRect(mSlots->mDropRow, primaryCol, imageSize, twistyRect, aPresContext,
    3871               0 :                     aRenderingContext, twistyContext);
    3872               0 :       nsMargin twistyMargin;
    3873               0 :       twistyContext->GetStyleMargin()->GetMargin(twistyMargin);
    3874               0 :       twistyRect.Inflate(twistyMargin);
    3875               0 :       currX += twistyRect.width;
    3876                 :     }
    3877                 : 
    3878               0 :     const nsStylePosition* stylePosition = feedbackContext->GetStylePosition();
    3879                 : 
    3880                 :     // Obtain the width for the drop feedback or use default value.
    3881                 :     nscoord width;
    3882               0 :     if (stylePosition->mWidth.GetUnit() == eStyleUnit_Coord)
    3883               0 :       width = stylePosition->mWidth.GetCoordValue();
    3884                 :     else {
    3885                 :       // Use default width 50px.
    3886               0 :       width = nsPresContext::CSSPixelsToAppUnits(50);
    3887                 :     }
    3888                 : 
    3889                 :     // Obtain the height for the drop feedback or use default value.
    3890                 :     nscoord height;
    3891               0 :     if (stylePosition->mHeight.GetUnit() == eStyleUnit_Coord)
    3892               0 :       height = stylePosition->mHeight.GetCoordValue();
    3893                 :     else {
    3894                 :       // Use default height 2px.
    3895               0 :       height = nsPresContext::CSSPixelsToAppUnits(2);
    3896                 :     }
    3897                 : 
    3898                 :     // Obtain the margins for the drop feedback and then deflate our rect
    3899                 :     // by that amount.
    3900               0 :     nsRect feedbackRect(currX, aDropFeedbackRect.y, width, height);
    3901               0 :     nsMargin margin;
    3902               0 :     feedbackContext->GetStyleMargin()->GetMargin(margin);
    3903               0 :     feedbackRect.Deflate(margin);
    3904                 : 
    3905               0 :     feedbackRect.y += (aDropFeedbackRect.height - height) / 2;
    3906                 : 
    3907                 :     // Finally paint the drop feedback.
    3908               0 :     PaintBackgroundLayer(feedbackContext, aPresContext, aRenderingContext, feedbackRect, aDirtyRect);
    3909                 :   }
    3910               0 : }
    3911                 : 
    3912                 : void
    3913               0 : nsTreeBodyFrame::PaintBackgroundLayer(nsStyleContext*      aStyleContext,
    3914                 :                                       nsPresContext*      aPresContext,
    3915                 :                                       nsRenderingContext& aRenderingContext,
    3916                 :                                       const nsRect&        aRect,
    3917                 :                                       const nsRect&        aDirtyRect)
    3918                 : {
    3919               0 :   const nsStyleBorder* myBorder = aStyleContext->GetStyleBorder();
    3920                 : 
    3921                 :   nsCSSRendering::PaintBackgroundWithSC(aPresContext, aRenderingContext,
    3922                 :                                         this, aDirtyRect, aRect,
    3923                 :                                         aStyleContext, *myBorder,
    3924               0 :                                         nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES);
    3925                 : 
    3926                 :   nsCSSRendering::PaintBorderWithStyleBorder(aPresContext, aRenderingContext,
    3927                 :                                              this, aDirtyRect, aRect,
    3928               0 :                                              *myBorder, mStyleContext);
    3929                 : 
    3930                 :   nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this,
    3931               0 :                                aDirtyRect, aRect, aStyleContext);
    3932               0 : }
    3933                 : 
    3934                 : // Scrolling
    3935                 : nsresult
    3936               0 : nsTreeBodyFrame::EnsureRowIsVisible(PRInt32 aRow)
    3937                 : {
    3938               0 :   ScrollParts parts = GetScrollParts();
    3939               0 :   nsresult rv = EnsureRowIsVisibleInternal(parts, aRow);
    3940               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3941               0 :   UpdateScrollbars(parts);
    3942               0 :   return rv;
    3943                 : }
    3944                 : 
    3945               0 : nsresult nsTreeBodyFrame::EnsureRowIsVisibleInternal(const ScrollParts& aParts, PRInt32 aRow)
    3946                 : {
    3947               0 :   if (!mView || !mPageLength)
    3948               0 :     return NS_OK;
    3949                 : 
    3950               0 :   if (mTopRowIndex <= aRow && mTopRowIndex+mPageLength > aRow)
    3951               0 :     return NS_OK;
    3952                 : 
    3953               0 :   if (aRow < mTopRowIndex)
    3954               0 :     ScrollToRowInternal(aParts, aRow);
    3955                 :   else {
    3956                 :     // Bring it just on-screen.
    3957               0 :     PRInt32 distance = aRow - (mTopRowIndex+mPageLength)+1;
    3958               0 :     ScrollToRowInternal(aParts, mTopRowIndex+distance);
    3959                 :   }
    3960                 : 
    3961               0 :   return NS_OK;
    3962                 : }
    3963                 : 
    3964                 : nsresult
    3965               0 : nsTreeBodyFrame::EnsureCellIsVisible(PRInt32 aRow, nsITreeColumn* aCol)
    3966                 : {
    3967               0 :   nsRefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
    3968               0 :   if (!col)
    3969               0 :     return NS_ERROR_INVALID_ARG;
    3970                 : 
    3971               0 :   ScrollParts parts = GetScrollParts();
    3972                 : 
    3973               0 :   nscoord result = -1;
    3974                 :   nsresult rv;
    3975                 : 
    3976                 :   nscoord columnPos;
    3977               0 :   rv = col->GetXInTwips(this, &columnPos);
    3978               0 :   if(NS_FAILED(rv)) return rv;
    3979                 : 
    3980                 :   nscoord columnWidth;
    3981               0 :   rv = col->GetWidthInTwips(this, &columnWidth);
    3982               0 :   if(NS_FAILED(rv)) return rv;
    3983                 : 
    3984                 :   // If the start of the column is before the
    3985                 :   // start of the horizontal view, then scroll
    3986               0 :   if (columnPos < mHorzPosition)
    3987               0 :     result = columnPos;
    3988                 :   // If the end of the column is past the end of 
    3989                 :   // the horizontal view, then scroll
    3990               0 :   else if ((columnPos + columnWidth) > (mHorzPosition + mInnerBox.width))
    3991               0 :     result = ((columnPos + columnWidth) - (mHorzPosition + mInnerBox.width)) + mHorzPosition;
    3992                 : 
    3993               0 :   if (result != -1) {
    3994               0 :     rv = ScrollHorzInternal(parts, result);
    3995               0 :     if(NS_FAILED(rv)) return rv;
    3996                 :   }
    3997                 : 
    3998               0 :   rv = EnsureRowIsVisibleInternal(parts, aRow);
    3999               0 :   NS_ENSURE_SUCCESS(rv, rv);
    4000               0 :   UpdateScrollbars(parts);
    4001               0 :   return rv;
    4002                 : }
    4003                 : 
    4004                 : nsresult
    4005               0 : nsTreeBodyFrame::ScrollToCell(PRInt32 aRow, nsITreeColumn* aCol)
    4006                 : {
    4007               0 :   ScrollParts parts = GetScrollParts();
    4008               0 :   nsresult rv = ScrollToRowInternal(parts, aRow);
    4009               0 :   NS_ENSURE_SUCCESS(rv, rv);
    4010                 : 
    4011               0 :   rv = ScrollToColumnInternal(parts, aCol);
    4012               0 :   NS_ENSURE_SUCCESS(rv, rv);
    4013                 : 
    4014               0 :   UpdateScrollbars(parts);
    4015               0 :   return rv;
    4016                 : }
    4017                 : 
    4018                 : nsresult
    4019               0 : nsTreeBodyFrame::ScrollToColumn(nsITreeColumn* aCol)
    4020                 : {
    4021               0 :   ScrollParts parts = GetScrollParts();
    4022               0 :   nsresult rv = ScrollToColumnInternal(parts, aCol);
    4023               0 :   NS_ENSURE_SUCCESS(rv, rv);
    4024               0 :   UpdateScrollbars(parts);
    4025               0 :   return rv;
    4026                 : }
    4027                 : 
    4028               0 : nsresult nsTreeBodyFrame::ScrollToColumnInternal(const ScrollParts& aParts,
    4029                 :                                                  nsITreeColumn* aCol)
    4030                 : {
    4031               0 :   nsRefPtr<nsTreeColumn> col = GetColumnImpl(aCol);
    4032               0 :   if (!col)
    4033               0 :     return NS_ERROR_INVALID_ARG;
    4034                 : 
    4035                 :   nscoord x;
    4036               0 :   nsresult rv = col->GetXInTwips(this, &x);
    4037               0 :   if (NS_FAILED(rv))
    4038               0 :     return rv;
    4039                 : 
    4040               0 :   return ScrollHorzInternal(aParts, x);
    4041                 : }
    4042                 : 
    4043                 : nsresult
    4044               0 : nsTreeBodyFrame::ScrollToHorizontalPosition(PRInt32 aHorizontalPosition)
    4045                 : {
    4046               0 :   ScrollParts parts = GetScrollParts();
    4047               0 :   PRInt32 position = nsPresContext::CSSPixelsToAppUnits(aHorizontalPosition);
    4048               0 :   nsresult rv = ScrollHorzInternal(parts, position);
    4049               0 :   NS_ENSURE_SUCCESS(rv, rv);
    4050               0 :   UpdateScrollbars(parts);
    4051               0 :   return rv;
    4052                 : }
    4053                 : 
    4054                 : nsresult
    4055               0 : nsTreeBodyFrame::ScrollToRow(PRInt32 aRow)
    4056                 : {
    4057               0 :   ScrollParts parts = GetScrollParts();
    4058               0 :   nsresult rv = ScrollToRowInternal(parts, aRow);
    4059               0 :   NS_ENSURE_SUCCESS(rv, rv);
    4060               0 :   UpdateScrollbars(parts);
    4061               0 :   return rv;
    4062                 : }
    4063                 : 
    4064               0 : nsresult nsTreeBodyFrame::ScrollToRowInternal(const ScrollParts& aParts, PRInt32 aRow)
    4065                 : {
    4066               0 :   ScrollInternal(aParts, aRow);
    4067                 : 
    4068               0 :   return NS_OK;
    4069                 : }
    4070                 : 
    4071                 : nsresult
    4072               0 : nsTreeBodyFrame::ScrollByLines(PRInt32 aNumLines)
    4073                 : {
    4074               0 :   if (!mView)
    4075               0 :     return NS_OK;
    4076                 : 
    4077               0 :   PRInt32 newIndex = mTopRowIndex + aNumLines;
    4078               0 :   if (newIndex < 0)
    4079               0 :     newIndex = 0;
    4080                 :   else {
    4081               0 :     PRInt32 lastPageTopRow = mRowCount - mPageLength;
    4082               0 :     if (newIndex > lastPageTopRow)
    4083               0 :       newIndex = lastPageTopRow;
    4084                 :   }
    4085               0 :   ScrollToRow(newIndex);
    4086                 :   
    4087               0 :   return NS_OK;
    4088                 : }
    4089                 : 
    4090                 : nsresult
    4091               0 : nsTreeBodyFrame::ScrollByPages(PRInt32 aNumPages)
    4092                 : {
    4093               0 :   if (!mView)
    4094               0 :     return NS_OK;
    4095                 : 
    4096               0 :   PRInt32 newIndex = mTopRowIndex + aNumPages * mPageLength;
    4097               0 :   if (newIndex < 0)
    4098               0 :     newIndex = 0;
    4099                 :   else {
    4100               0 :     PRInt32 lastPageTopRow = mRowCount - mPageLength;
    4101               0 :     if (newIndex > lastPageTopRow)
    4102               0 :       newIndex = lastPageTopRow;
    4103                 :   }
    4104               0 :   ScrollToRow(newIndex);
    4105                 :     
    4106               0 :   return NS_OK;
    4107                 : }
    4108                 : 
    4109                 : nsresult
    4110               0 : nsTreeBodyFrame::ScrollInternal(const ScrollParts& aParts, PRInt32 aRow)
    4111                 : {
    4112               0 :   if (!mView)
    4113               0 :     return NS_OK;
    4114                 : 
    4115               0 :   PRInt32 delta = aRow - mTopRowIndex;
    4116                 : 
    4117               0 :   if (delta > 0) {
    4118               0 :     if (mTopRowIndex == (mRowCount - mPageLength + 1))
    4119               0 :       return NS_OK;
    4120                 :   }
    4121                 :   else {
    4122               0 :     if (mTopRowIndex == 0)
    4123               0 :       return NS_OK;
    4124                 :   }
    4125                 : 
    4126               0 :   mTopRowIndex += delta;
    4127                 : 
    4128               0 :   Invalidate();
    4129                 : 
    4130               0 :   PostScrollEvent();
    4131               0 :   return NS_OK;
    4132                 : }
    4133                 : 
    4134                 : nsresult
    4135               0 : nsTreeBodyFrame::ScrollHorzInternal(const ScrollParts& aParts, PRInt32 aPosition)
    4136                 : {
    4137               0 :   if (!mView || !aParts.mColumnsScrollFrame || !aParts.mHScrollbar)
    4138               0 :     return NS_OK;
    4139                 : 
    4140               0 :   if (aPosition == mHorzPosition)
    4141               0 :     return NS_OK;
    4142                 : 
    4143               0 :   if (aPosition < 0 || aPosition > mHorzWidth)
    4144               0 :     return NS_OK;
    4145                 : 
    4146               0 :   nsRect bounds = aParts.mColumnsFrame->GetRect();
    4147               0 :   if (aPosition > (mHorzWidth - bounds.width)) 
    4148               0 :     aPosition = mHorzWidth - bounds.width;
    4149                 : 
    4150               0 :   mHorzPosition = aPosition;
    4151                 : 
    4152               0 :   Invalidate();
    4153                 : 
    4154                 :   // Update the column scroll view
    4155                 :   aParts.mColumnsScrollFrame->ScrollTo(nsPoint(mHorzPosition, 0),
    4156               0 :                                        nsIScrollableFrame::INSTANT);
    4157                 : 
    4158                 :   // And fire off an event about it all
    4159               0 :   PostScrollEvent();
    4160               0 :   return NS_OK;
    4161                 : }
    4162                 : 
    4163                 : NS_IMETHODIMP
    4164               0 : nsTreeBodyFrame::ScrollbarButtonPressed(nsScrollbarFrame* aScrollbar, PRInt32 aOldIndex, PRInt32 aNewIndex)
    4165                 : {
    4166               0 :   ScrollParts parts = GetScrollParts();
    4167                 : 
    4168               0 :   if (aScrollbar == parts.mVScrollbar) {
    4169               0 :     if (aNewIndex > aOldIndex)
    4170               0 :       ScrollToRowInternal(parts, mTopRowIndex+1);
    4171               0 :     else if (aNewIndex < aOldIndex)
    4172               0 :       ScrollToRowInternal(parts, mTopRowIndex-1);
    4173                 :   } else {
    4174               0 :     ScrollHorzInternal(parts, aNewIndex);
    4175                 :   }
    4176                 : 
    4177               0 :   UpdateScrollbars(parts);
    4178                 : 
    4179               0 :   return NS_OK;
    4180                 : }
    4181                 :   
    4182                 : NS_IMETHODIMP
    4183               0 : nsTreeBodyFrame::PositionChanged(nsScrollbarFrame* aScrollbar, PRInt32 aOldIndex, PRInt32& aNewIndex)
    4184                 : {
    4185               0 :   ScrollParts parts = GetScrollParts();
    4186                 :   
    4187               0 :   if (aOldIndex == aNewIndex)
    4188               0 :     return NS_OK;
    4189                 : 
    4190                 :   // Vertical Scrollbar 
    4191               0 :   if (parts.mVScrollbar == aScrollbar) {
    4192               0 :     nscoord rh = nsPresContext::AppUnitsToIntCSSPixels(mRowHeight);
    4193                 : 
    4194               0 :     nscoord newrow = aNewIndex/rh;
    4195               0 :     ScrollInternal(parts, newrow);
    4196                 :   // Horizontal Scrollbar
    4197               0 :   } else if (parts.mHScrollbar == aScrollbar) {
    4198               0 :     ScrollHorzInternal(parts, aNewIndex);
    4199                 :   }
    4200                 : 
    4201               0 :   UpdateScrollbars(parts);
    4202               0 :   return NS_OK;
    4203                 : }
    4204                 : 
    4205                 : // The style cache.
    4206                 : nsStyleContext*
    4207               0 : nsTreeBodyFrame::GetPseudoStyleContext(nsIAtom* aPseudoElement)
    4208                 : {
    4209                 :   return mStyleCache.GetStyleContext(this, PresContext(), mContent,
    4210                 :                                      mStyleContext, aPseudoElement,
    4211               0 :                                      mScratchArray);
    4212                 : }
    4213                 : 
    4214                 : // Our comparator for resolving our complex pseudos
    4215                 : bool
    4216               0 : nsTreeBodyFrame::PseudoMatches(nsCSSSelector* aSelector)
    4217                 : {
    4218                 :   // Iterate the class list.  For each item in the list, see if
    4219                 :   // it is contained in our scratch array.  If we have a miss, then
    4220                 :   // we aren't a match.  If all items in the class list are
    4221                 :   // present in the scratch array, then we have a match.
    4222               0 :   nsAtomList* curr = aSelector->mClassList;
    4223               0 :   while (curr) {
    4224                 :     PRInt32 index;
    4225               0 :     mScratchArray->GetIndexOf(curr->mAtom, &index);
    4226               0 :     if (index == -1) {
    4227               0 :       return false;
    4228                 :     }
    4229               0 :     curr = curr->mNext;
    4230                 :   }
    4231               0 :   return true;
    4232                 : }
    4233                 : 
    4234                 : nsIContent*
    4235               0 : nsTreeBodyFrame::GetBaseElement()
    4236                 : {
    4237               0 :   nsIFrame* parent = GetParent();
    4238               0 :   while (parent) {
    4239               0 :     nsIContent* content = parent->GetContent();
    4240               0 :     if (content) {
    4241               0 :       nsINodeInfo* ni = content->NodeInfo();
    4242                 : 
    4243               0 :       if (ni->Equals(nsGkAtoms::tree, kNameSpaceID_XUL) ||
    4244               0 :           (ni->Equals(nsGkAtoms::select) &&
    4245               0 :            content->IsHTML()))
    4246               0 :         return content;
    4247                 :     }
    4248                 : 
    4249               0 :     parent = parent->GetParent();
    4250                 :   }
    4251                 : 
    4252               0 :   return nsnull;
    4253                 : }
    4254                 : 
    4255                 : nsresult
    4256               0 : nsTreeBodyFrame::ClearStyleAndImageCaches()
    4257                 : {
    4258               0 :   mStyleCache.Clear();
    4259               0 :   mImageCache.EnumerateRead(CancelImageRequest, this);
    4260               0 :   mImageCache.Clear();
    4261               0 :   return NS_OK;
    4262                 : }
    4263                 : 
    4264                 : /* virtual */ void
    4265               0 : nsTreeBodyFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
    4266                 : {
    4267               0 :   nsLeafBoxFrame::DidSetStyleContext(aOldStyleContext);
    4268                 : 
    4269                 :   // Clear the style cache; the pointers are no longer even valid
    4270               0 :   mStyleCache.Clear();
    4271                 :   // XXX The following is hacky, but it's not incorrect,
    4272                 :   // and appears to fix a few bugs with style changes, like text zoom and
    4273                 :   // dpi changes
    4274               0 :   mIndentation = GetIndentation();
    4275               0 :   mRowHeight = GetRowHeight();
    4276               0 :   mStringWidth = -1;
    4277               0 : }
    4278                 : 
    4279                 : bool 
    4280               0 : nsTreeBodyFrame::OffsetForHorzScroll(nsRect& rect, bool clip)
    4281                 : {
    4282               0 :   rect.x -= mHorzPosition;
    4283                 : 
    4284                 :   // Scrolled out before
    4285               0 :   if (rect.XMost() <= mInnerBox.x)
    4286               0 :     return false;
    4287                 : 
    4288                 :   // Scrolled out after
    4289               0 :   if (rect.x > mInnerBox.XMost())
    4290               0 :     return false;
    4291                 : 
    4292               0 :   if (clip) {
    4293               0 :     nscoord leftEdge = NS_MAX(rect.x, mInnerBox.x);
    4294               0 :     nscoord rightEdge = NS_MIN(rect.XMost(), mInnerBox.XMost());
    4295               0 :     rect.x = leftEdge;
    4296               0 :     rect.width = rightEdge - leftEdge;
    4297                 : 
    4298                 :     // Should have returned false above
    4299               0 :     NS_ASSERTION(rect.width >= 0, "horz scroll code out of sync");
    4300                 :   }
    4301                 : 
    4302               0 :   return true;
    4303                 : }
    4304                 : 
    4305                 : bool
    4306               0 : nsTreeBodyFrame::CanAutoScroll(PRInt32 aRowIndex)
    4307                 : {
    4308                 :   // Check first for partially visible last row.
    4309               0 :   if (aRowIndex == mRowCount - 1) {
    4310               0 :     nscoord y = mInnerBox.y + (aRowIndex - mTopRowIndex) * mRowHeight;
    4311               0 :     if (y < mInnerBox.height && y + mRowHeight > mInnerBox.height)
    4312               0 :       return true;
    4313                 :   }
    4314                 : 
    4315               0 :   if (aRowIndex > 0 && aRowIndex < mRowCount - 1)
    4316               0 :     return true;
    4317                 : 
    4318               0 :   return false;
    4319                 : }
    4320                 : 
    4321                 : // Given a dom event, figure out which row in the tree the mouse is over,
    4322                 : // if we should drop before/after/on that row or we should auto-scroll.
    4323                 : // Doesn't query the content about if the drag is allowable, that's done elsewhere.
    4324                 : //
    4325                 : // For containers, we break up the vertical space of the row as follows: if in
    4326                 : // the topmost 25%, the drop is _before_ the row the mouse is over; if in the
    4327                 : // last 25%, _after_; in the middle 50%, we consider it a drop _on_ the container.
    4328                 : //
    4329                 : // For non-containers, if the mouse is in the top 50% of the row, the drop is
    4330                 : // _before_ and the bottom 50% _after_
    4331                 : void 
    4332               0 : nsTreeBodyFrame::ComputeDropPosition(nsGUIEvent* aEvent, PRInt32* aRow, PRInt16* aOrient,
    4333                 :                                      PRInt16* aScrollLines)
    4334                 : {
    4335               0 :   *aOrient = -1;
    4336               0 :   *aScrollLines = 0;
    4337                 : 
    4338                 :   // Convert the event's point to our coordinates.  We want it in
    4339                 :   // the coordinates of our inner box's coordinates.
    4340               0 :   nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
    4341               0 :   PRInt32 xTwips = pt.x - mInnerBox.x;
    4342               0 :   PRInt32 yTwips = pt.y - mInnerBox.y;
    4343                 : 
    4344               0 :   *aRow = GetRowAt(xTwips, yTwips);
    4345               0 :   if (*aRow >=0) {
    4346                 :     // Compute the top/bottom of the row in question.
    4347               0 :     PRInt32 yOffset = yTwips - mRowHeight * (*aRow - mTopRowIndex);
    4348                 :    
    4349               0 :     bool isContainer = false;
    4350               0 :     mView->IsContainer (*aRow, &isContainer);
    4351               0 :     if (isContainer) {
    4352                 :       // for a container, use a 25%/50%/25% breakdown
    4353               0 :       if (yOffset < mRowHeight / 4)
    4354               0 :         *aOrient = nsITreeView::DROP_BEFORE;
    4355               0 :       else if (yOffset > mRowHeight - (mRowHeight / 4))
    4356               0 :         *aOrient = nsITreeView::DROP_AFTER;
    4357                 :       else
    4358               0 :         *aOrient = nsITreeView::DROP_ON;
    4359                 :     }
    4360                 :     else {
    4361                 :       // for a non-container use a 50%/50% breakdown
    4362               0 :       if (yOffset < mRowHeight / 2)
    4363               0 :         *aOrient = nsITreeView::DROP_BEFORE;
    4364                 :       else
    4365               0 :         *aOrient = nsITreeView::DROP_AFTER;
    4366                 :     }
    4367                 :   }
    4368                 : 
    4369               0 :   if (CanAutoScroll(*aRow)) {
    4370                 :     // Get the max value from the look and feel service.
    4371                 :     PRInt32 scrollLinesMax =
    4372               0 :       LookAndFeel::GetInt(LookAndFeel::eIntID_TreeScrollLinesMax, 0);
    4373               0 :     scrollLinesMax--;
    4374               0 :     if (scrollLinesMax < 0)
    4375               0 :       scrollLinesMax = 0;
    4376                 : 
    4377                 :     // Determine if we're w/in a margin of the top/bottom of the tree during a drag.
    4378                 :     // This will ultimately cause us to scroll, but that's done elsewhere.
    4379               0 :     nscoord height = (3 * mRowHeight) / 4;
    4380               0 :     if (yTwips < height) {
    4381                 :       // scroll up
    4382               0 :       *aScrollLines = NSToIntRound(-scrollLinesMax * (1 - (float)yTwips / height) - 1);
    4383                 :     }
    4384               0 :     else if (yTwips > mRect.height - height) {
    4385                 :       // scroll down
    4386               0 :       *aScrollLines = NSToIntRound(scrollLinesMax * (1 - (float)(mRect.height - yTwips) / height) + 1);
    4387                 :     }
    4388                 :   }
    4389               0 : } // ComputeDropPosition
    4390                 : 
    4391                 : void
    4392               0 : nsTreeBodyFrame::OpenCallback(nsITimer *aTimer, void *aClosure)
    4393                 : {
    4394               0 :   nsTreeBodyFrame* self = static_cast<nsTreeBodyFrame*>(aClosure);
    4395               0 :   if (self) {
    4396               0 :     aTimer->Cancel();
    4397               0 :     self->mSlots->mTimer = nsnull;
    4398                 : 
    4399               0 :     if (self->mSlots->mDropRow >= 0) {
    4400               0 :       self->mSlots->mArray.AppendElement(self->mSlots->mDropRow);
    4401               0 :       self->mView->ToggleOpenState(self->mSlots->mDropRow);
    4402                 :     }
    4403                 :   }
    4404               0 : }
    4405                 : 
    4406                 : void
    4407               0 : nsTreeBodyFrame::CloseCallback(nsITimer *aTimer, void *aClosure)
    4408                 : {
    4409               0 :   nsTreeBodyFrame* self = static_cast<nsTreeBodyFrame*>(aClosure);
    4410               0 :   if (self) {
    4411               0 :     aTimer->Cancel();
    4412               0 :     self->mSlots->mTimer = nsnull;
    4413                 : 
    4414               0 :     for (PRUint32 i = self->mSlots->mArray.Length(); i--; ) {
    4415               0 :       if (self->mView)
    4416               0 :         self->mView->ToggleOpenState(self->mSlots->mArray[i]);
    4417                 :     }
    4418               0 :     self->mSlots->mArray.Clear();
    4419                 :   }
    4420               0 : }
    4421                 : 
    4422                 : void
    4423               0 : nsTreeBodyFrame::LazyScrollCallback(nsITimer *aTimer, void *aClosure)
    4424                 : {
    4425               0 :   nsTreeBodyFrame* self = static_cast<nsTreeBodyFrame*>(aClosure);
    4426               0 :   if (self) {
    4427               0 :     aTimer->Cancel();
    4428               0 :     self->mSlots->mTimer = nsnull;
    4429                 : 
    4430               0 :     if (self->mView) {
    4431                 :       // Set a new timer to scroll the tree repeatedly.
    4432                 :       self->CreateTimer(LookAndFeel::eIntID_TreeScrollDelay,
    4433                 :                         ScrollCallback, nsITimer::TYPE_REPEATING_SLACK,
    4434               0 :                         getter_AddRefs(self->mSlots->mTimer));
    4435               0 :       self->ScrollByLines(self->mSlots->mScrollLines);
    4436                 :       // ScrollByLines may have deleted |self|.
    4437                 :     }
    4438                 :   }
    4439               0 : }
    4440                 : 
    4441                 : void
    4442               0 : nsTreeBodyFrame::ScrollCallback(nsITimer *aTimer, void *aClosure)
    4443                 : {
    4444               0 :   nsTreeBodyFrame* self = static_cast<nsTreeBodyFrame*>(aClosure);
    4445               0 :   if (self) {
    4446                 :     // Don't scroll if we are already at the top or bottom of the view.
    4447               0 :     if (self->mView && self->CanAutoScroll(self->mSlots->mDropRow)) {
    4448               0 :       self->ScrollByLines(self->mSlots->mScrollLines);
    4449                 :     }
    4450                 :     else {
    4451               0 :       aTimer->Cancel();
    4452               0 :       self->mSlots->mTimer = nsnull;
    4453                 :     }
    4454                 :   }
    4455               0 : }
    4456                 : 
    4457                 : NS_IMETHODIMP
    4458               0 : nsTreeBodyFrame::ScrollEvent::Run()
    4459                 : {
    4460               0 :   if (mInner) {
    4461               0 :     mInner->FireScrollEvent();
    4462                 :   }
    4463               0 :   return NS_OK;
    4464                 : }
    4465                 : 
    4466                 : 
    4467                 : void
    4468               0 : nsTreeBodyFrame::FireScrollEvent()
    4469                 : {
    4470               0 :   mScrollEvent.Forget();
    4471               0 :   nsScrollbarEvent event(true, NS_SCROLL_EVENT, nsnull);
    4472                 :   // scroll events fired at elements don't bubble
    4473               0 :   event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
    4474               0 :   nsEventDispatcher::Dispatch(GetContent(), PresContext(), &event);
    4475               0 : }
    4476                 : 
    4477                 : void
    4478               0 : nsTreeBodyFrame::PostScrollEvent()
    4479                 : {
    4480               0 :   if (mScrollEvent.IsPending())
    4481               0 :     return;
    4482                 : 
    4483               0 :   nsRefPtr<ScrollEvent> ev = new ScrollEvent(this);
    4484               0 :   if (NS_FAILED(NS_DispatchToCurrentThread(ev))) {
    4485               0 :     NS_WARNING("failed to dispatch ScrollEvent");
    4486                 :   } else {
    4487               0 :     mScrollEvent = ev;
    4488                 :   }
    4489                 : }
    4490                 : 
    4491                 : void
    4492               0 : nsTreeBodyFrame::DetachImageListeners()
    4493                 : {
    4494               0 :   mCreatedListeners.Clear();
    4495               0 : }
    4496                 : 
    4497                 : void
    4498               0 : nsTreeBodyFrame::RemoveTreeImageListener(nsTreeImageListener* aListener)
    4499                 : {
    4500               0 :   if (aListener) {
    4501               0 :     mCreatedListeners.RemoveEntry(aListener);
    4502                 :   }
    4503               0 : }
    4504                 : 
    4505                 : #ifdef ACCESSIBILITY
    4506                 : void
    4507               0 : nsTreeBodyFrame::FireRowCountChangedEvent(PRInt32 aIndex, PRInt32 aCount)
    4508                 : {
    4509               0 :   nsCOMPtr<nsIContent> content(GetBaseElement());
    4510               0 :   if (!content)
    4511                 :     return;
    4512                 : 
    4513               0 :   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(content->OwnerDoc());
    4514               0 :   if (!domDoc)
    4515                 :     return;
    4516                 : 
    4517               0 :   nsCOMPtr<nsIDOMEvent> event;
    4518               0 :   domDoc->CreateEvent(NS_LITERAL_STRING("datacontainerevents"),
    4519               0 :                       getter_AddRefs(event));
    4520                 : 
    4521               0 :   nsCOMPtr<nsIDOMDataContainerEvent> treeEvent(do_QueryInterface(event));
    4522               0 :   if (!treeEvent)
    4523                 :     return;
    4524                 : 
    4525               0 :   event->InitEvent(NS_LITERAL_STRING("TreeRowCountChanged"), true, false);
    4526                 : 
    4527                 :   // Set 'index' data - the row index rows are changed from.
    4528                 :   nsCOMPtr<nsIWritableVariant> indexVariant(
    4529               0 :     do_CreateInstance("@mozilla.org/variant;1"));
    4530               0 :   if (!indexVariant)
    4531                 :     return;
    4532                 : 
    4533               0 :   indexVariant->SetAsInt32(aIndex);
    4534               0 :   treeEvent->SetData(NS_LITERAL_STRING("index"), indexVariant);
    4535                 : 
    4536                 :   // Set 'count' data - the number of changed rows.
    4537                 :   nsCOMPtr<nsIWritableVariant> countVariant(
    4538               0 :     do_CreateInstance("@mozilla.org/variant;1"));
    4539               0 :   if (!countVariant)
    4540                 :     return;
    4541                 : 
    4542               0 :   countVariant->SetAsInt32(aCount);
    4543               0 :   treeEvent->SetData(NS_LITERAL_STRING("count"), countVariant);
    4544                 : 
    4545                 :   // Fire an event.
    4546               0 :   nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
    4547               0 :   if (!privateEvent)
    4548                 :     return;
    4549                 : 
    4550               0 :   privateEvent->SetTrusted(true);
    4551                 : 
    4552               0 :   nsRefPtr<nsAsyncDOMEvent> plevent = new nsAsyncDOMEvent(content, event);
    4553               0 :   if (!plevent)
    4554                 :     return;
    4555                 : 
    4556               0 :   plevent->PostDOMEvent();
    4557                 : }
    4558                 : 
    4559                 : void
    4560               0 : nsTreeBodyFrame::FireInvalidateEvent(PRInt32 aStartRowIdx, PRInt32 aEndRowIdx,
    4561                 :                                      nsITreeColumn *aStartCol,
    4562                 :                                      nsITreeColumn *aEndCol)
    4563                 : {
    4564               0 :   nsCOMPtr<nsIContent> content(GetBaseElement());
    4565               0 :   if (!content)
    4566                 :     return;
    4567                 : 
    4568               0 :   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(content->OwnerDoc());
    4569               0 :   if (!domDoc)
    4570                 :     return;
    4571                 : 
    4572               0 :   nsCOMPtr<nsIDOMEvent> event;
    4573               0 :   domDoc->CreateEvent(NS_LITERAL_STRING("datacontainerevents"),
    4574               0 :                       getter_AddRefs(event));
    4575                 : 
    4576               0 :   nsCOMPtr<nsIDOMDataContainerEvent> treeEvent(do_QueryInterface(event));
    4577               0 :   if (!treeEvent)
    4578                 :     return;
    4579                 : 
    4580               0 :   event->InitEvent(NS_LITERAL_STRING("TreeInvalidated"), true, false);
    4581                 : 
    4582               0 :   if (aStartRowIdx != -1 && aEndRowIdx != -1) {
    4583                 :     // Set 'startrow' data - the start index of invalidated rows.
    4584                 :     nsCOMPtr<nsIWritableVariant> startRowVariant(
    4585               0 :       do_CreateInstance("@mozilla.org/variant;1"));
    4586               0 :     if (!startRowVariant)
    4587                 :       return;
    4588                 : 
    4589               0 :     startRowVariant->SetAsInt32(aStartRowIdx);
    4590               0 :     treeEvent->SetData(NS_LITERAL_STRING("startrow"), startRowVariant);
    4591                 : 
    4592                 :     // Set 'endrow' data - the end index of invalidated rows.
    4593                 :     nsCOMPtr<nsIWritableVariant> endRowVariant(
    4594               0 :       do_CreateInstance("@mozilla.org/variant;1"));
    4595               0 :     if (!endRowVariant)
    4596                 :       return;
    4597                 : 
    4598               0 :     endRowVariant->SetAsInt32(aEndRowIdx);
    4599               0 :     treeEvent->SetData(NS_LITERAL_STRING("endrow"), endRowVariant);
    4600                 :   }
    4601                 : 
    4602               0 :   if (aStartCol && aEndCol) {
    4603                 :     // Set 'startcolumn' data - the start index of invalidated rows.
    4604                 :     nsCOMPtr<nsIWritableVariant> startColVariant(
    4605               0 :       do_CreateInstance("@mozilla.org/variant;1"));
    4606               0 :     if (!startColVariant)
    4607                 :       return;
    4608                 : 
    4609               0 :     PRInt32 startColIdx = 0;
    4610               0 :     nsresult rv = aStartCol->GetIndex(&startColIdx);
    4611               0 :     if (NS_FAILED(rv))
    4612                 :       return;
    4613                 : 
    4614               0 :     startColVariant->SetAsInt32(startColIdx);
    4615               0 :     treeEvent->SetData(NS_LITERAL_STRING("startcolumn"), startColVariant);
    4616                 : 
    4617                 :     // Set 'endcolumn' data - the start index of invalidated rows.
    4618                 :     nsCOMPtr<nsIWritableVariant> endColVariant(
    4619               0 :       do_CreateInstance("@mozilla.org/variant;1"));
    4620               0 :     if (!endColVariant)
    4621                 :       return;
    4622                 : 
    4623               0 :     PRInt32 endColIdx = 0;
    4624               0 :     rv = aEndCol->GetIndex(&endColIdx);
    4625               0 :     if (NS_FAILED(rv))
    4626                 :       return;
    4627                 : 
    4628               0 :     endColVariant->SetAsInt32(endColIdx);
    4629               0 :     treeEvent->SetData(NS_LITERAL_STRING("endcolumn"), endColVariant);
    4630                 :   }
    4631                 : 
    4632                 :   // Fire an event.
    4633               0 :   nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
    4634               0 :   if (!privateEvent)
    4635                 :     return;
    4636                 : 
    4637               0 :   privateEvent->SetTrusted(true);
    4638                 : 
    4639               0 :   nsRefPtr<nsAsyncDOMEvent> plevent = new nsAsyncDOMEvent(content, event);
    4640               0 :   if (plevent)
    4641               0 :     plevent->PostDOMEvent();
    4642                 : }
    4643                 : #endif
    4644                 : 
    4645                 : class nsOverflowChecker : public nsRunnable
    4646               0 : {
    4647                 : public:
    4648               0 :   nsOverflowChecker(nsTreeBodyFrame* aFrame) : mFrame(aFrame) {}
    4649               0 :   NS_IMETHOD Run()
    4650                 :   {
    4651               0 :     if (mFrame.IsAlive()) {
    4652               0 :       nsTreeBodyFrame* tree = static_cast<nsTreeBodyFrame*>(mFrame.GetFrame());
    4653               0 :       nsTreeBodyFrame::ScrollParts parts = tree->GetScrollParts();
    4654               0 :       tree->CheckOverflow(parts);
    4655                 :     }
    4656               0 :     return NS_OK;
    4657                 :   }
    4658                 : private:
    4659                 :   nsWeakFrame mFrame;
    4660                 : };
    4661                 : 
    4662                 : bool
    4663               0 : nsTreeBodyFrame::FullScrollbarsUpdate(bool aNeedsFullInvalidation)
    4664                 : {
    4665               0 :   ScrollParts parts = GetScrollParts();
    4666               0 :   nsWeakFrame weakFrame(this);
    4667               0 :   nsWeakFrame weakColumnsFrame(parts.mColumnsFrame);
    4668               0 :   UpdateScrollbars(parts);
    4669               0 :   NS_ENSURE_TRUE(weakFrame.IsAlive(), false);
    4670               0 :   if (aNeedsFullInvalidation) {
    4671               0 :     Invalidate();
    4672                 :   }
    4673               0 :   InvalidateScrollbars(parts, weakColumnsFrame);
    4674               0 :   NS_ENSURE_TRUE(weakFrame.IsAlive(), false);
    4675               0 :   nsContentUtils::AddScriptRunner(new nsOverflowChecker(this));
    4676               0 :   return weakFrame.IsAlive();
    4677                 : }
    4678                 : 
    4679                 : nsresult
    4680               0 : nsTreeBodyFrame::OnImageIsAnimated(imgIRequest* aRequest)
    4681                 : {
    4682                 :   nsLayoutUtils::RegisterImageRequest(PresContext(),
    4683               0 :                                       aRequest, nsnull);
    4684                 : 
    4685               0 :   return NS_OK;
    4686                 : }

Generated by: LCOV version 1.7