LCOV - code coverage report
Current view: top level - layout/xul/tree - nsTreeBodyFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 2430 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 136 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13