Bug 140759 - tree cell content is not aligned to the right when tree direction is right to left; r=roc,gavin sr=roc
authorEhsan Akhgari <ehsan.akhgari@gmail.com>
Tue, 13 Jan 2009 21:30:06 +0330
changeset 23612 a77147340730dfec448277ff3f11350174c037bb
parent 23611 02963082440153977d64eafe4ab8a7ac063666b3
child 23613 6e089951b91535c9bdd7ea9b752dc01ac53e2be7
push id4637
push userehsan.akhgari@gmail.com
push dateTue, 13 Jan 2009 18:02:29 +0000
treeherdermozilla-central@6e089951b915 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, gavin, roc
bugs140759
milestone1.9.2a1pre
Bug 140759 - tree cell content is not aligned to the right when tree direction is right to left; r=roc,gavin sr=roc
layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
layout/xul/base/src/tree/src/nsTreeColumns.cpp
toolkit/content/widgets/tree.xml
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
@@ -26,16 +26,17 @@
  *   Jan Varga <varga@ku.sk>
  *   Dean Tessman <dean_tessman@hotmail.com>
  *   Brian Ryner <bryner@brianryner.com>
  *   Blake Ross <blaker@netscape.com>
  *   Pierre Chanial <pierrechanial@netscape.net>
  *   Rene Pronk <r.pronk@its.tudelft.nl>
  *   Nate Nielsen <nielsen@memberwebs.com>
  *   Mark Banner <mark@standard8.demon.co.uk>
+ *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -1134,16 +1135,17 @@ nsresult
 nsTreeBodyFrame::GetCoordsForCellItem(PRInt32 aRow, nsITreeColumn* aCol, const nsACString& aElement, 
                                       PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight)
 {
   *aX = 0;
   *aY = 0;
   *aWidth = 0;
   *aHeight = 0;
 
+  PRBool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
   nscoord currX = mInnerBox.x - mHorzPosition;
 
   // The Rect for the requested item. 
   nsRect theRect;
 
   nsPresContext* presContext = PresContext();
 
   for (nsTreeColumn* currCol = mColumns->GetFirstColumn(); currCol; currCol = currCol->GetNext()) {
@@ -1207,17 +1209,18 @@ nsTreeBodyFrame::GetCoordsForCellItem(PR
 
     if (currCol->IsPrimary()) {
       // If the current Column is a Primary, then we need to take into account the indentation
       // and possibly a twisty. 
 
       // The amount of indentation is the indentation width (|mIndentation|) by the level. 
       PRInt32 level;
       mView->GetLevel(aRow, &level);
-      cellX += mIndentation * level;
+      if (!isRTL)
+        cellX += mIndentation * level;
       remainWidth -= mIndentation * level;
 
       // Find the twisty rect by computing its size. 
       nsRect imageRect;
       nsRect twistyRect(cellRect);
       nsStyleContext* twistyContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreetwisty);
       GetTwistyRect(aRow, currCol, imageRect, twistyRect, presContext,
                     *rc, twistyContext);
@@ -1230,18 +1233,19 @@ nsTreeBodyFrame::GetCoordsForCellItem(PR
       
       // Now we need to add in the margins of the twisty element, so that we 
       // can find the offset of the next element in the cell. 
       nsMargin twistyMargin;
       twistyContext->GetStyleMargin()->GetMargin(twistyMargin);
       twistyRect.Inflate(twistyMargin);
 
       // Adjust our working X value with the twisty width (image size, margins,
-      // borders, padding. 
-      cellX += twistyRect.width;
+      // borders, padding.
+      if (!isRTL)
+        cellX += twistyRect.width;
     }
 
     // Cell Image
     nsStyleContext* imageContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeimage);
 
     nsRect imageSize = GetImageSize(aRow, currCol, PR_FALSE, imageContext);
     if (NS_LITERAL_CSTRING("image").Equals(aElement)) {
       theRect = imageSize;
@@ -1251,17 +1255,18 @@ nsTreeBodyFrame::GetCoordsForCellItem(PR
     }
 
     // Add in the margins of the cell image.
     nsMargin imageMargin;
     imageContext->GetStyleMargin()->GetMargin(imageMargin);
     imageSize.Inflate(imageMargin);
 
     // Increment cellX by the image width
-    cellX += imageSize.width;
+    if (!isRTL)
+      cellX += imageSize.width;
     
     // Cell Text 
     nsAutoString cellText;
     mView->GetCellText(aRow, currCol, cellText);
     // We're going to measure this text so we need to ensure bidi is enabled if
     // necessary
     CheckTextForBidi(cellText);
 
@@ -1306,16 +1311,19 @@ nsTreeBodyFrame::GetCoordsForCellItem(PR
       // If the text is not cropped, the text is smaller than the available 
       // space and we set the text rect to be that width. 
       textRect.width = totalTextWidth;
     }
 
     theRect = textRect;
   }
 
+  if (isRTL)
+    theRect.x = mInnerBox.width - theRect.x - theRect.width;
+
   *aX = nsPresContext::AppUnitsToIntCSSPixels(theRect.x);
   *aY = nsPresContext::AppUnitsToIntCSSPixels(theRect.y);
   *aWidth = nsPresContext::AppUnitsToIntCSSPixels(theRect.width);
   *aHeight = nsPresContext::AppUnitsToIntCSSPixels(theRect.height);
 
   return NS_OK;
 }
 
@@ -1540,27 +1548,30 @@ nsTreeBodyFrame::GetItemWithinCellAt(nsc
   if (aX < cellRect.x || aX >= cellRect.x + cellRect.width) {
     // The user clicked within the cell's margins/borders/padding.  This constitutes a click on the cell.
     return nsCSSAnonBoxes::moztreecell;
   }
 
   nscoord currX = cellRect.x;
   nscoord remainingWidth = cellRect.width;
 
-  // XXX Handle right alignment hit testing.
+  // Handle right alignment hit testing.
+  PRBool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
 
   if (aColumn->IsPrimary()) {
     // If we're the primary column, we have indentation and a twisty.
     PRInt32 level;
     mView->GetLevel(aRowIndex, &level);
 
-    currX += mIndentation*level;
+    if (!isRTL)
+      currX += mIndentation*level;
     remainingWidth -= mIndentation*level;
 
-    if (aX < currX) {
+    if (isRTL && aX > currX + remainingWidth ||
+        !isRTL && aX < currX) {
       // The user clicked within the indentation.
       return nsCSSAnonBoxes::moztreecell;
     }
 
     // Always leave space for the twisty.
     nsRect twistyRect(currX, cellRect.y, remainingWidth, cellRect.height);
     PRBool hasTwisty = PR_FALSE;
     PRBool isContainer = PR_FALSE;
@@ -1584,49 +1595,55 @@ nsTreeBodyFrame::GetItemWithinCellAt(nsc
                   *rc, twistyContext);
 
     // We will treat a click as hitting the twisty if it happens on the margins, borders, padding,
     // or content of the twisty object.  By allowing a "slop" into the margin, we make it a little
     // bit easier for a user to hit the twisty.  (We don't want to be too picky here.)
     nsMargin twistyMargin;
     twistyContext->GetStyleMargin()->GetMargin(twistyMargin);
     twistyRect.Inflate(twistyMargin);
+    if (isRTL)
+      twistyRect.x = currX + remainingWidth - twistyRect.width;
 
     // Now we test to see if aX is actually within the twistyRect.  If it is, and if the item should
     // have a twisty, then we return "twisty".  If it is within the rect but we shouldn't have a twisty,
     // then we return "cell".
     if (aX >= twistyRect.x && aX < twistyRect.x + twistyRect.width) {
       if (hasTwisty)
         return nsCSSAnonBoxes::moztreetwisty;
       else
         return nsCSSAnonBoxes::moztreecell;
     }
 
-    currX += twistyRect.width;
+    if (!isRTL)
+      currX += twistyRect.width;
     remainingWidth -= twistyRect.width;    
   }
   
   // Now test to see if the user hit the icon for the cell.
   nsRect iconRect(currX, cellRect.y, remainingWidth, cellRect.height);
   
   // Resolve style for the image.
   nsStyleContext* imageContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeimage);
 
   nsRect iconSize = GetImageSize(aRowIndex, aColumn, PR_FALSE, imageContext);
   nsMargin imageMargin;
   imageContext->GetStyleMargin()->GetMargin(imageMargin);
   iconSize.Inflate(imageMargin);
   iconRect.width = iconSize.width;
+  if (isRTL)
+    iconRect.x = currX + remainingWidth - iconRect.width;
 
   if (aX >= iconRect.x && aX < iconRect.x + iconRect.width) {
     // The user clicked on the image.
     return nsCSSAnonBoxes::moztreeimage;
   }
 
-  currX += iconRect.width;
+  if (!isRTL)
+    currX += iconRect.width;
   remainingWidth -= iconRect.width;    
 
   nsAutoString cellText;
   mView->GetCellText(aRowIndex, aColumn, cellText);
   // We're going to measure this text so we need to ensure bidi is enabled if
   // necessary
   CheckTextForBidi(cellText);
 
@@ -1641,16 +1658,18 @@ nsTreeBodyFrame::GetItemWithinCellAt(nsc
   AdjustForBorderPadding(textContext, textRect);
 
   nsCOMPtr<nsIRenderingContext> renderingContext;
   PresContext()->PresShell()->CreateRenderingContext(this, getter_AddRefs(renderingContext));
 
   nsLayoutUtils::SetFontFromStyle(renderingContext, textContext);
 
   AdjustForCellText(cellText, aRowIndex, aColumn, *renderingContext, textRect);
+  if (isRTL)
+    textRect.x = currX + remainingWidth - textRect.width;
 
   if (aX >= textRect.x && aX < textRect.x + textRect.width)
     return nsCSSAnonBoxes::moztreecelltext;
   else
     return nsCSSAnonBoxes::moztreecell;
 }
 
 void
@@ -3123,16 +3142,18 @@ nsTreeBodyFrame::PaintCell(PRInt32      
   // XXX Automatically fill in the following props: open, closed, container, leaf, selected, focused, and the col ID.
   PrefillPropertyArray(aRowIndex, aColumn);
   mView->GetCellProperties(aRowIndex, aColumn, mScratchArray);
 
   // Resolve style for the cell.  It contains all the info we need to lay ourselves
   // out and to paint.
   nsStyleContext* cellContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecell);
 
+  PRBool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
+
   // Obtain the margins for the cell and then deflate our rect by that 
   // amount.  The cell is assumed to be contained within the deflated rect.
   nsRect cellRect(aCellRect);
   nsMargin cellMargin;
   cellContext->GetStyleMargin()->GetMargin(cellMargin);
   cellRect.Deflate(cellMargin);
 
   // Paint our borders and background for our row rect.
@@ -3140,29 +3161,29 @@ nsTreeBodyFrame::PaintCell(PRInt32      
 
   // Adjust the rect for its border and padding.
   AdjustForBorderPadding(cellContext, cellRect);
 
   nscoord currX = cellRect.x;
   nscoord remainingWidth = cellRect.width;
 
   // Now we paint the contents of the cells.
-  // Text alignment determines the order in which we paint.  
-  // LEFT means paint from left to right.
-  // RIGHT means paint from right to left.
-  // XXX Implement RIGHT alignment!
+  // Directionality of the tree determines the order in which we paint.  
+  // NS_STYLE_DIRECTION_LTR means paint from left to right.
+  // NS_STYLE_DIRECTION_RTL means paint from right to left.
 
   if (aColumn->IsPrimary()) {
     // If we're the primary column, we need to indent and paint the twisty and any connecting lines
     // between siblings.
 
     PRInt32 level;
     mView->GetLevel(aRowIndex, &level);
 
-    currX += mIndentation * level;
+    if (!isRTL)
+      currX += mIndentation * level;
     remainingWidth -= mIndentation * level;
 
     // Resolve the style to use for the connecting lines.
     nsStyleContext* lineContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeline);
     
     if (mIndentation && level &&
         lineContext->GetStyleVisibility()->IsVisibleOrCollapsed()) {
       // Paint the thread lines.
@@ -3192,23 +3213,29 @@ nsTreeBodyFrame::PaintCell(PRInt32      
         color = lineContext->GetStyleColor()->mColor;
       }
       aRenderingContext.SetColor(color);
       PRUint8 style;
       style = borderStyle->GetBorderStyle(NS_SIDE_LEFT);
       aRenderingContext.SetLineStyle(ConvertBorderStyleToLineStyle(style));
 
       nscoord srcX = currX + twistyRect.width - mIndentation / 2;
+      if (isRTL)
+        srcX = currX + remainingWidth - (srcX - cellRect.x);
       nscoord lineY = (aRowIndex - mTopRowIndex) * mRowHeight + aPt.y;
 
       // Don't paint off our cell.
       if (srcX <= cellRect.x + cellRect.width) {
         nscoord destX = currX + twistyRect.width;
         if (destX > cellRect.x + cellRect.width)
           destX = cellRect.x + cellRect.width;
+        if (isRTL) {
+          srcX = currX + remainingWidth - (srcX - cellRect.x);
+          destX = currX + remainingWidth - (destX - cellRect.x);
+        }
         aRenderingContext.DrawLine(srcX, lineY + mRowHeight / 2, destX, lineY + mRowHeight / 2);
       }
 
       PRInt32 currentParent = aRowIndex;
       for (PRInt32 i = level; i > 0; i--) {
         if (srcX <= cellRect.x + cellRect.width) {
           // Paint full vertical line only if we have next sibling.
           PRBool hasNextSibling;
@@ -3284,16 +3311,18 @@ nsTreeBodyFrame::PaintTwisty(PRInt32    
                              nsPresContext*      aPresContext,
                              nsIRenderingContext& aRenderingContext,
                              const nsRect&        aDirtyRect,
                              nscoord&             aRemainingWidth,
                              nscoord&             aCurrX)
 {
   NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
 
+  PRBool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
+  nscoord rightEdge = aCurrX + aRemainingWidth;
   // Paint the twisty, but only if we are a non-empty container.
   PRBool shouldPaint = PR_FALSE;
   PRBool isContainer = PR_FALSE;
   mView->IsContainer(aRowIndex, &isContainer);
   if (isContainer) {
     PRBool isContainerEmpty = PR_FALSE;
     mView->IsContainerEmpty(aRowIndex, &isContainerEmpty);
     if (!isContainerEmpty)
@@ -3314,37 +3343,42 @@ nsTreeBodyFrame::PaintTwisty(PRInt32    
   nsITheme* theme = GetTwistyRect(aRowIndex, aColumn, imageSize, twistyRect,
                                   aPresContext, aRenderingContext, twistyContext);
 
   // Subtract out the remaining width.  This is done even when we don't actually paint a twisty in 
   // this cell, so that cells in different rows still line up.
   nsRect copyRect(twistyRect);
   copyRect.Inflate(twistyMargin);
   aRemainingWidth -= copyRect.width;
-  aCurrX += copyRect.width;
+  if (!isRTL)
+    aCurrX += copyRect.width;
 
   if (shouldPaint) {
     // Paint our borders and background for our image rect.
     PaintBackgroundLayer(twistyContext, aPresContext, aRenderingContext, twistyRect, aDirtyRect);
 
     if (theme) {
+      if (isRTL)
+        twistyRect.x = rightEdge - twistyRect.width;
       // yeah, I know it says we're drawing a background, but a twisty is really a fg
       // object since it doesn't have anything that gecko would want to draw over it. Besides,
       // we have to prevent imagelib from drawing it.
       nsRect dirty;
       dirty.IntersectRect(twistyRect, aDirtyRect);
       theme->DrawWidgetBackground(&aRenderingContext, this, 
                                   twistyContext->GetStyleDisplay()->mAppearance, twistyRect, dirty);
     }
     else {
       // Time to paint the twisty.
       // Adjust the rect for its border and padding.
       nsMargin bp(0,0,0,0);
       GetBorderPadding(twistyContext, bp);
       twistyRect.Deflate(bp);
+      if (isRTL)
+        twistyRect.x = rightEdge - twistyRect.width;
       imageSize.Deflate(bp);
 
       // Get the image for drawing.
       nsCOMPtr<imgIContainer> image;
       PRBool useImageRegion = PR_TRUE;
       GetImage(aRowIndex, aColumn, PR_TRUE, twistyContext, useImageRegion, getter_AddRefs(image));
       if (image) {
         nsPoint pt = twistyRect.TopLeft();
@@ -3369,16 +3403,18 @@ nsTreeBodyFrame::PaintImage(PRInt32     
                             nsPresContext*       aPresContext,
                             nsIRenderingContext& aRenderingContext,
                             const nsRect&        aDirtyRect,
                             nscoord&             aRemainingWidth,
                             nscoord&             aCurrX)
 {
   NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
 
+  PRBool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
+  nscoord rightEdge = aCurrX + aRemainingWidth;
   // Resolve style for the image.
   nsStyleContext* imageContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeimage);
 
   // Obtain the margins for the image and then deflate our rect by that
   // amount.  The image is assumed to be contained within the deflated rect.
   nsRect imageRect(aImageRect);
   nsMargin imageMargin;
   imageContext->GetStyleMargin()->GetMargin(imageMargin);
@@ -3424,16 +3460,18 @@ nsTreeBodyFrame::PaintImage(PRInt32     
       // If this column is not a cycler, we won't center the image horizontally.
       // We adjust the imageRect width so that the image is placed at the start
       // of the cell.
       imageRect.width = destRect.width;
     }
   }
 
   if (image) {
+    if (isRTL)
+      imageRect.x = rightEdge - imageRect.width;
     // Paint our borders and background for our image rect
     PaintBackgroundLayer(imageContext, aPresContext, aRenderingContext, imageRect, aDirtyRect);
 
     // The destRect x and y have not been set yet. Let's do that now.
     // Initially, we use the imageRect x and y.
     destRect.x = imageRect.x;
     destRect.y = imageRect.y;
 
@@ -3483,30 +3521,34 @@ nsTreeBodyFrame::PaintImage(PRInt32     
 
     nsLayoutUtils::DrawImage(&aRenderingContext, image,
         wholeImageDest, destRect, destRect.TopLeft(), aDirtyRect);
   }
 
   // Update the aRemainingWidth and aCurrX values.
   imageRect.Inflate(imageMargin);
   aRemainingWidth -= imageRect.width;
-  aCurrX += imageRect.width;
+  if (!isRTL)
+    aCurrX += imageRect.width;
 }
 
 void
 nsTreeBodyFrame::PaintText(PRInt32              aRowIndex,
                            nsTreeColumn*        aColumn,
                            const nsRect&        aTextRect,
                            nsPresContext*      aPresContext,
                            nsIRenderingContext& aRenderingContext,
                            const nsRect&        aDirtyRect,
                            nscoord&             aCurrX)
 {
   NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
 
+  PRBool isRTL = GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
+  nscoord rightEdge = aTextRect.XMost();
+
   // Now obtain the text for our cell.
   nsAutoString text;
   mView->GetCellText(aRowIndex, aColumn, text);
   // We're going to paint this text so we need to ensure bidi is enabled if
   // necessary
   CheckTextForBidi(text);
 
   if (text.Length() == 0)
@@ -3546,23 +3588,26 @@ nsTreeBodyFrame::PaintText(PRInt32      
   // Set our font.
   aRenderingContext.SetFont(fontMet);
 
   AdjustForCellText(text, aRowIndex, aColumn, aRenderingContext, textRect);
 
   // Subtract out the remaining width.
   nsRect copyRect(textRect);
   copyRect.Inflate(textMargin);
-  aCurrX += copyRect.width;
+  if (!isRTL)
+    aCurrX += copyRect.width;
 
   textRect.Inflate(bp);
   PaintBackgroundLayer(textContext, aPresContext, aRenderingContext, textRect, aDirtyRect);
 
   // Time to paint our text.
   textRect.Deflate(bp);
+  if (isRTL)
+    textRect.x = rightEdge - textRect.width;
 
   // Set our color.
   aRenderingContext.SetColor(textContext->GetStyleColor()->mColor);
 
   // Draw decorations.
   PRUint8 decorations = textContext->GetStyleTextReset()->mTextDecoration;
 
   nscoord offset;
@@ -3597,30 +3642,35 @@ nsTreeBodyFrame::PaintCheckbox(PRInt32  
                                nsIRenderingContext& aRenderingContext,
                                const nsRect&        aDirtyRect)
 {
   NS_PRECONDITION(aColumn && aColumn->GetFrame(this), "invalid column passed");
 
   // Resolve style for the checkbox.
   nsStyleContext* checkboxContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecheckbox);
 
+  nscoord rightEdge = aCheckboxRect.XMost();
+
   // Obtain the margins for the checkbox and then deflate our rect by that 
   // amount.  The checkbox is assumed to be contained within the deflated rect.
   nsRect checkboxRect(aCheckboxRect);
   nsMargin checkboxMargin;
   checkboxContext->GetStyleMargin()->GetMargin(checkboxMargin);
   checkboxRect.Deflate(checkboxMargin);
   
   nsRect imageSize = GetImageSize(aRowIndex, aColumn, PR_TRUE, checkboxContext);
 
   if (imageSize.height > checkboxRect.height)
     imageSize.height = checkboxRect.height;
   if (imageSize.width > checkboxRect.width)
     imageSize.width = checkboxRect.width;
 
+  if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL)
+    checkboxRect.x = rightEdge - checkboxRect.width;
+
   // Paint our borders and background for our image rect.
   PaintBackgroundLayer(checkboxContext, aPresContext, aRenderingContext, checkboxRect, aDirtyRect);
 
   // Time to paint the checkbox.
   // Adjust the rect for its border and padding.
   nsMargin bp(0,0,0,0);
   GetBorderPadding(checkboxContext, bp);
   checkboxRect.Deflate(bp);
@@ -3687,17 +3737,20 @@ nsTreeBodyFrame::PaintProgressMeter(PRIn
 
     PRInt32 rv;
     PRInt32 intValue = value.ToInteger(&rv);
     if (intValue < 0)
       intValue = 0;
     else if (intValue > 100)
       intValue = 100;
 
-    meterRect.width = NSToCoordRound((float)intValue / 100 * meterRect.width);
+    nscoord meterWidth = NSToCoordRound((float)intValue / 100 * meterRect.width);
+    if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL)
+      meterRect.x += meterRect.width - meterWidth; // right align
+    meterRect.width = meterWidth;
     PRBool useImageRegion = PR_TRUE;
     nsCOMPtr<imgIContainer> image;
     GetImage(aRowIndex, aColumn, PR_TRUE, meterContext, useImageRegion, getter_AddRefs(image));
     if (image) {
       PRInt32 width, height;
       image->GetWidth(&width);
       image->GetHeight(&height);
       nsSize size(width*nsIDeviceContext::AppUnitsPerCSSPixel(),
--- a/layout/xul/base/src/tree/src/nsTreeColumns.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeColumns.cpp
@@ -17,16 +17,17 @@
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 2003
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Dave Hyatt <hyatt@mozilla.org> (Original Author)
  *   Jan Varga <varga@ku.sk>
+ *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -141,20 +142,23 @@ nsresult
 nsTreeColumn::GetRect(nsTreeBodyFrame* aBodyFrame, nscoord aY, nscoord aHeight, nsRect* aResult)
 {
   nsIFrame* frame = GetFrame(aBodyFrame);
   if (!frame) {
     *aResult = nsRect();
     return NS_ERROR_FAILURE;
   }
 
+  PRBool isRTL = aBodyFrame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
   *aResult = frame->GetRect();
   aResult->y = aY;
   aResult->height = aHeight;
-  if (IsLastVisible(aBodyFrame))
+  if (isRTL)
+    aResult->x += aBodyFrame->mAdjustWidth;
+  else if (IsLastVisible(aBodyFrame))
     aResult->width += aBodyFrame->mAdjustWidth;
   return NS_OK;
 }
 
 nsresult
 nsTreeColumn::GetXInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult)
 {
   nsIFrame* frame = GetFrame(aBodyFrame);
--- a/toolkit/content/widgets/tree.xml
+++ b/toolkit/content/widgets/tree.xml
@@ -256,16 +256,23 @@
             var seltype = this.selType;
             if (seltype == "cell" || seltype == "text")
               return seltype;
             return null;
           ]]>
         </getter>
       </property>
 
+      <constructor><![CDATA[
+          // Bindings that extend this one wouldn't inherit the
+          // chromedir attribute if it would only be set in <content>.
+          this.setAttribute("chromedir", "]]>&locale.dir;<![CDATA[");
+        ]]>
+      </constructor>
+
       <method name="_getNextColumn">
         <parameter name="row"/>
         <parameter name="left"/>
         <body><![CDATA[
           var col = this.view.selection.currentColumn;
           if (col) {
             col = left ? col.getPrevious() : col.getNext();
           }
@@ -336,33 +343,47 @@
             if (this._editingColumn)
               this.stopEditing();
 
             var input = this.inputField;
 
             var box = this.treeBoxObject;
             box.ensureCellIsVisible(row, column);
 
-            var outx = {}, outy = {}, outwidth = {}, outheight = {};
+            // Get the coordinates of the text inside the cell.
+            var textx = {}, texty = {}, textwidth = {}, textheight = {};
             var coords = box.getCoordsForCellItem(row, column, "text",
-                                                  outx, outy, outwidth, outheight);
+                                                  textx, texty, textwidth, textheight);
 
+            // Get the coordinates of the cell itself.
+            var cellx = {}, cellwidth = {};
+            coords = box.getCoordsForCellItem(row, column, "cell",
+                                              cellx, {}, cellwidth, {});
+
+            // Calculate the top offset of the textbox.
             var style = window.getComputedStyle(input, "");
             var topadj = parseInt(style.borderTopWidth) + parseInt(style.paddingTop);
-            input.top = outy.value - topadj;
+            input.top = texty.value - topadj;
 
-            var left = outx.value;
+            // The leftside of the textbox is aligned to the left side of the text
+            // in LTR mode, and left side of the cell in RTL mode.
+            var left, widthdiff;
+            if (style.direction == "rtl") {
+              left = cellx.value;
+              widthdiff = cellx.value + cellwidth.value - textx.value - textwidth.value;
+            } else {
+              left = textx.value;
+              widthdiff = textx.value - cellx.value;
+            }
+
             input.left = left;
-            input.height = outheight.value + topadj +
+            input.height = textheight.value + topadj +
                            parseInt(style.borderBottomWidth) +
                            parseInt(style.paddingBottom);
-
-            coords = box.getCoordsForCellItem(row, column, "cell",
-                                              outx, outy, outwidth, outheight);
-            input.width = outwidth.value - (left - outx.value);
+            input.width = cellwidth.value - widthdiff;
             input.hidden = false;
 
             input.value = this.view.getCellText(row, column);
             var selectText = function selectText() {
               input.select();
               input.inputField.focus();
             }
             setTimeout(selectText, 0);